<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<!--[if IE]><meta http-equiv="X-UA-Compatible" content="IE=edge"><![endif]-->
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="generator" content="Asciidoctor 1.5.5">
<title>JDK</title>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Open+Sans:300,300italic,400,400italic,600,600italic%7CNoto+Serif:400,400italic,700,700italic%7CDroid+Sans+Mono:400,700">
<style>
/* Asciidoctor default stylesheet | MIT License | http://asciidoctor.org */
/* Remove comment around @import statement below when using as a custom stylesheet */
/*@import "https://fonts.googleapis.com/css?family=Open+Sans:300,300italic,400,400italic,600,600italic%7CNoto+Serif:400,400italic,700,700italic%7CDroid+Sans+Mono:400,700";*/
article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block}
audio,canvas,video{display:inline-block}
audio:not([controls]){display:none;height:0}
[hidden],template{display:none}
script{display:none!important}
html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}
a{background:transparent}
a:focus{outline:thin dotted}
a:active,a:hover{outline:0}
h1{font-size:2em;margin:.67em 0}
abbr[title]{border-bottom:1px dotted}
b,strong{font-weight:bold}
dfn{font-style:italic}
hr{-moz-box-sizing:content-box;box-sizing:content-box;height:0}
mark{background:#ff0;color:#000}
code,kbd,pre,samp{font-family:monospace;font-size:1em}
pre{white-space:pre-wrap}
q{quotes:"\201C" "\201D" "\2018" "\2019"}
small{font-size:80%}
sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}
sup{top:-.5em}
sub{bottom:-.25em}
img{border:0}
svg:not(:root){overflow:hidden}
figure{margin:0}
fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}
legend{border:0;padding:0}
button,input,select,textarea{font-family:inherit;font-size:100%;margin:0}
button,input{line-height:normal}
button,select{text-transform:none}
button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer}
button[disabled],html input[disabled]{cursor:default}
input[type="checkbox"],input[type="radio"]{box-sizing:border-box;padding:0}
input[type="search"]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}
input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none}
button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}
textarea{overflow:auto;vertical-align:top}
table{border-collapse:collapse;border-spacing:0}
*,*:before,*:after{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}
html,body{font-size:100%}
body{background:#fff;color:rgba(0,0,0,.8);padding:0;margin:0;font-family:"Noto Serif","DejaVu Serif",serif;font-weight:400;font-style:normal;line-height:1;position:relative;cursor:auto;tab-size:4;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased}
a:hover{cursor:pointer}
img,object,embed{max-width:100%;height:auto}
object,embed{height:100%}
img{-ms-interpolation-mode:bicubic}
.left{float:left!important}
.right{float:right!important}
.text-left{text-align:left!important}
.text-right{text-align:right!important}
.text-center{text-align:center!important}
.text-justify{text-align:justify!important}
.hide{display:none}
img,object,svg{display:inline-block;vertical-align:middle}
textarea{height:auto;min-height:50px}
select{width:100%}
.center{margin-left:auto;margin-right:auto}
.spread{width:100%}
p.lead,.paragraph.lead>p,#preamble>.sectionbody>.paragraph:first-of-type p{font-size:1.21875em;line-height:1.6}
.subheader,.admonitionblock td.content>.title,.audioblock>.title,.exampleblock>.title,.imageblock>.title,.listingblock>.title,.literalblock>.title,.stemblock>.title,.openblock>.title,.paragraph>.title,.quoteblock>.title,table.tableblock>.title,.verseblock>.title,.videoblock>.title,.dlist>.title,.olist>.title,.ulist>.title,.qlist>.title,.hdlist>.title{line-height:1.45;color:#7a2518;font-weight:400;margin-top:0;margin-bottom:.25em}
div,dl,dt,dd,ul,ol,li,h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6,pre,form,p,blockquote,th,td{margin:0;padding:0;direction:ltr}
a{color:#2156a5;text-decoration:underline;line-height:inherit}
a:hover,a:focus{color:#1d4b8f}
a img{border:none}
p{font-family:inherit;font-weight:400;font-size:1em;line-height:1.6;margin-bottom:1.25em;text-rendering:optimizeLegibility}
p aside{font-size:.875em;line-height:1.35;font-style:italic}
h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{font-family:"Open Sans","DejaVu Sans",sans-serif;font-weight:300;font-style:normal;color:#ba3925;text-rendering:optimizeLegibility;margin-top:1em;margin-bottom:.5em;line-height:1.0125em}
h1 small,h2 small,h3 small,#toctitle small,.sidebarblock>.content>.title small,h4 small,h5 small,h6 small{font-size:60%;color:#e99b8f;line-height:0}
h1{font-size:2.125em}
h2{font-size:1.6875em}
h3,#toctitle,.sidebarblock>.content>.title{font-size:1.375em}
h4,h5{font-size:1.125em}
h6{font-size:1em}
hr{border:solid #ddddd8;border-width:1px 0 0;clear:both;margin:1.25em 0 1.1875em;height:0}
em,i{font-style:italic;line-height:inherit}
strong,b{font-weight:bold;line-height:inherit}
small{font-size:60%;line-height:inherit}
code{font-family:"Droid Sans Mono","DejaVu Sans Mono",monospace;font-weight:400;color:rgba(0,0,0,.9)}
ul,ol,dl{font-size:1em;line-height:1.6;margin-bottom:1.25em;list-style-position:outside;font-family:inherit}
ul,ol,ul.no-bullet,ol.no-bullet{margin-left:1.5em}
ul li ul,ul li ol{margin-left:1.25em;margin-bottom:0;font-size:1em}
ul.square li ul,ul.circle li ul,ul.disc li ul{list-style:inherit}
ul.square{list-style-type:square}
ul.circle{list-style-type:circle}
ul.disc{list-style-type:disc}
ul.no-bullet{list-style:none}
ol li ul,ol li ol{margin-left:1.25em;margin-bottom:0}
dl dt{margin-bottom:.3125em;font-weight:bold}
dl dd{margin-bottom:1.25em}
abbr,acronym{text-transform:uppercase;font-size:90%;color:rgba(0,0,0,.8);border-bottom:1px dotted #ddd;cursor:help}
abbr{text-transform:none}
blockquote{margin:0 0 1.25em;padding:.5625em 1.25em 0 1.1875em;border-left:1px solid #ddd}
blockquote cite{display:block;font-size:.9375em;color:rgba(0,0,0,.6)}
blockquote cite:before{content:"\2014 \0020"}
blockquote cite a,blockquote cite a:visited{color:rgba(0,0,0,.6)}
blockquote,blockquote p{line-height:1.6;color:rgba(0,0,0,.85)}
@media only screen and (min-width:768px){h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{line-height:1.2}
h1{font-size:2.75em}
h2{font-size:2.3125em}
h3,#toctitle,.sidebarblock>.content>.title{font-size:1.6875em}
h4{font-size:1.4375em}}
table{background:#fff;margin-bottom:1.25em;border:solid 1px #dedede}
table thead,table tfoot{background:#f7f8f7;font-weight:bold}
table thead tr th,table thead tr td,table tfoot tr th,table tfoot tr td{padding:.5em .625em .625em;font-size:inherit;color:rgba(0,0,0,.8);text-align:left}
table tr th,table tr td{padding:.5625em .625em;font-size:inherit;color:rgba(0,0,0,.8)}
table tr.even,table tr.alt,table tr:nth-of-type(even){background:#f8f8f7}
table thead tr th,table tfoot tr th,table tbody tr td,table tr td,table tfoot tr td{display:table-cell;line-height:1.6}
h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{line-height:1.2;word-spacing:-.05em}
h1 strong,h2 strong,h3 strong,#toctitle strong,.sidebarblock>.content>.title strong,h4 strong,h5 strong,h6 strong{font-weight:400}
.clearfix:before,.clearfix:after,.float-group:before,.float-group:after{content:" ";display:table}
.clearfix:after,.float-group:after{clear:both}
*:not(pre)>code{font-size:.9375em;font-style:normal!important;letter-spacing:0;padding:.1em .5ex;word-spacing:-.15em;background-color:#f7f7f8;-webkit-border-radius:4px;border-radius:4px;line-height:1.45;text-rendering:optimizeSpeed;word-wrap:break-word}
*:not(pre)>code.nobreak{word-wrap:normal}
*:not(pre)>code.nowrap{white-space:nowrap}
pre,pre>code{line-height:1.45;color:rgba(0,0,0,.9);font-family:"Droid Sans Mono","DejaVu Sans Mono",monospace;font-weight:400;text-rendering:optimizeSpeed}
em em{font-style:normal}
strong strong{font-weight:400}
.keyseq{color:rgba(51,51,51,.8)}
kbd{font-family:"Droid Sans Mono","DejaVu Sans Mono",monospace;display:inline-block;color:rgba(0,0,0,.8);font-size:.65em;line-height:1.45;background-color:#f7f7f7;border:1px solid #ccc;-webkit-border-radius:3px;border-radius:3px;-webkit-box-shadow:0 1px 0 rgba(0,0,0,.2),0 0 0 .1em white inset;box-shadow:0 1px 0 rgba(0,0,0,.2),0 0 0 .1em #fff inset;margin:0 .15em;padding:.2em .5em;vertical-align:middle;position:relative;top:-.1em;white-space:nowrap}
.keyseq kbd:first-child{margin-left:0}
.keyseq kbd:last-child{margin-right:0}
.menuseq,.menu{color:rgba(0,0,0,.8)}
b.button:before,b.button:after{position:relative;top:-1px;font-weight:400}
b.button:before{content:"[";padding:0 3px 0 2px}
b.button:after{content:"]";padding:0 2px 0 3px}
p a>code:hover{color:rgba(0,0,0,.9)}
#header,#content,#footnotes,#footer{width:100%;margin-left:auto;margin-right:auto;margin-top:0;margin-bottom:0;max-width:62.5em;*zoom:1;position:relative;padding-left:.9375em;padding-right:.9375em}
#header:before,#header:after,#content:before,#content:after,#footnotes:before,#footnotes:after,#footer:before,#footer:after{content:" ";display:table}
#header:after,#content:after,#footnotes:after,#footer:after{clear:both}
#content{margin-top:1.25em}
#content:before{content:none}
#header>h1:first-child{color:rgba(0,0,0,.85);margin-top:2.25rem;margin-bottom:0}
#header>h1:first-child+#toc{margin-top:8px;border-top:1px solid #ddddd8}
#header>h1:only-child,body.toc2 #header>h1:nth-last-child(2){border-bottom:1px solid #ddddd8;padding-bottom:8px}
#header .details{border-bottom:1px solid #ddddd8;line-height:1.45;padding-top:.25em;padding-bottom:.25em;padding-left:.25em;color:rgba(0,0,0,.6);display:-ms-flexbox;display:-webkit-flex;display:flex;-ms-flex-flow:row wrap;-webkit-flex-flow:row wrap;flex-flow:row wrap}
#header .details span:first-child{margin-left:-.125em}
#header .details span.email a{color:rgba(0,0,0,.85)}
#header .details br{display:none}
#header .details br+span:before{content:"\00a0\2013\00a0"}
#header .details br+span.author:before{content:"\00a0\22c5\00a0";color:rgba(0,0,0,.85)}
#header .details br+span#revremark:before{content:"\00a0|\00a0"}
#header #revnumber{text-transform:capitalize}
#header #revnumber:after{content:"\00a0"}
#content>h1:first-child:not([class]){color:rgba(0,0,0,.85);border-bottom:1px solid #ddddd8;padding-bottom:8px;margin-top:0;padding-top:1rem;margin-bottom:1.25rem}
#toc{border-bottom:1px solid #efefed;padding-bottom:.5em}
#toc>ul{margin-left:.125em}
#toc ul.sectlevel0>li>a{font-style:italic}
#toc ul.sectlevel0 ul.sectlevel1{margin:.5em 0}
#toc ul{font-family:"Open Sans","DejaVu Sans",sans-serif;list-style-type:none}
#toc li{line-height:1.3334;margin-top:.3334em}
#toc a{text-decoration:none}
#toc a:active{text-decoration:underline}
#toctitle{color:#7a2518;font-size:1.2em}
@media only screen and (min-width:768px){#toctitle{font-size:1.375em}
body.toc2{padding-left:15em;padding-right:0}
#toc.toc2{margin-top:0!important;background-color:#f8f8f7;position:fixed;width:15em;left:0;top:0;border-right:1px solid #efefed;border-top-width:0!important;border-bottom-width:0!important;z-index:1000;padding:1.25em 1em;height:100%;overflow:auto}
#toc.toc2 #toctitle{margin-top:0;margin-bottom:.8rem;font-size:1.2em}
#toc.toc2>ul{font-size:.9em;margin-bottom:0}
#toc.toc2 ul ul{margin-left:0;padding-left:1em}
#toc.toc2 ul.sectlevel0 ul.sectlevel1{padding-left:0;margin-top:.5em;margin-bottom:.5em}
body.toc2.toc-right{padding-left:0;padding-right:15em}
body.toc2.toc-right #toc.toc2{border-right-width:0;border-left:1px solid #efefed;left:auto;right:0}}
@media only screen and (min-width:1280px){body.toc2{padding-left:20em;padding-right:0}
#toc.toc2{width:20em}
#toc.toc2 #toctitle{font-size:1.375em}
#toc.toc2>ul{font-size:.95em}
#toc.toc2 ul ul{padding-left:1.25em}
body.toc2.toc-right{padding-left:0;padding-right:20em}}
#content #toc{border-style:solid;border-width:1px;border-color:#e0e0dc;margin-bottom:1.25em;padding:1.25em;background:#f8f8f7;-webkit-border-radius:4px;border-radius:4px}
#content #toc>:first-child{margin-top:0}
#content #toc>:last-child{margin-bottom:0}
#footer{max-width:100%;background-color:rgba(0,0,0,.8);padding:1.25em}
#footer-text{color:rgba(255,255,255,.8);line-height:1.44}
.sect1{padding-bottom:.625em}
@media only screen and (min-width:768px){.sect1{padding-bottom:1.25em}}
.sect1+.sect1{border-top:1px solid #efefed}
#content h1>a.anchor,h2>a.anchor,h3>a.anchor,#toctitle>a.anchor,.sidebarblock>.content>.title>a.anchor,h4>a.anchor,h5>a.anchor,h6>a.anchor{position:absolute;z-index:1001;width:1.5ex;margin-left:-1.5ex;display:block;text-decoration:none!important;visibility:hidden;text-align:center;font-weight:400}
#content h1>a.anchor:before,h2>a.anchor:before,h3>a.anchor:before,#toctitle>a.anchor:before,.sidebarblock>.content>.title>a.anchor:before,h4>a.anchor:before,h5>a.anchor:before,h6>a.anchor:before{content:"\00A7";font-size:.85em;display:block;padding-top:.1em}
#content h1:hover>a.anchor,#content h1>a.anchor:hover,h2:hover>a.anchor,h2>a.anchor:hover,h3:hover>a.anchor,#toctitle:hover>a.anchor,.sidebarblock>.content>.title:hover>a.anchor,h3>a.anchor:hover,#toctitle>a.anchor:hover,.sidebarblock>.content>.title>a.anchor:hover,h4:hover>a.anchor,h4>a.anchor:hover,h5:hover>a.anchor,h5>a.anchor:hover,h6:hover>a.anchor,h6>a.anchor:hover{visibility:visible}
#content h1>a.link,h2>a.link,h3>a.link,#toctitle>a.link,.sidebarblock>.content>.title>a.link,h4>a.link,h5>a.link,h6>a.link{color:#ba3925;text-decoration:none}
#content h1>a.link:hover,h2>a.link:hover,h3>a.link:hover,#toctitle>a.link:hover,.sidebarblock>.content>.title>a.link:hover,h4>a.link:hover,h5>a.link:hover,h6>a.link:hover{color:#a53221}
.audioblock,.imageblock,.literalblock,.listingblock,.stemblock,.videoblock{margin-bottom:1.25em}
.admonitionblock td.content>.title,.audioblock>.title,.exampleblock>.title,.imageblock>.title,.listingblock>.title,.literalblock>.title,.stemblock>.title,.openblock>.title,.paragraph>.title,.quoteblock>.title,table.tableblock>.title,.verseblock>.title,.videoblock>.title,.dlist>.title,.olist>.title,.ulist>.title,.qlist>.title,.hdlist>.title{text-rendering:optimizeLegibility;text-align:left;font-family:"Noto Serif","DejaVu Serif",serif;font-size:1rem;font-style:italic}
table.tableblock>caption.title{white-space:nowrap;overflow:visible;max-width:0}
.paragraph.lead>p,#preamble>.sectionbody>.paragraph:first-of-type p{color:rgba(0,0,0,.85)}
table.tableblock #preamble>.sectionbody>.paragraph:first-of-type p{font-size:inherit}
.admonitionblock>table{border-collapse:separate;border:0;background:none;width:100%}
.admonitionblock>table td.icon{text-align:center;width:80px}
.admonitionblock>table td.icon img{max-width:none}
.admonitionblock>table td.icon .title{font-weight:bold;font-family:"Open Sans","DejaVu Sans",sans-serif;text-transform:uppercase}
.admonitionblock>table td.content{padding-left:1.125em;padding-right:1.25em;border-left:1px solid #ddddd8;color:rgba(0,0,0,.6)}
.admonitionblock>table td.content>:last-child>:last-child{margin-bottom:0}
.exampleblock>.content{border-style:solid;border-width:1px;border-color:#e6e6e6;margin-bottom:1.25em;padding:1.25em;background:#fff;-webkit-border-radius:4px;border-radius:4px}
.exampleblock>.content>:first-child{margin-top:0}
.exampleblock>.content>:last-child{margin-bottom:0}
.sidebarblock{border-style:solid;border-width:1px;border-color:#e0e0dc;margin-bottom:1.25em;padding:1.25em;background:#f8f8f7;-webkit-border-radius:4px;border-radius:4px}
.sidebarblock>:first-child{margin-top:0}
.sidebarblock>:last-child{margin-bottom:0}
.sidebarblock>.content>.title{color:#7a2518;margin-top:0;text-align:center}
.exampleblock>.content>:last-child>:last-child,.exampleblock>.content .olist>ol>li:last-child>:last-child,.exampleblock>.content .ulist>ul>li:last-child>:last-child,.exampleblock>.content .qlist>ol>li:last-child>:last-child,.sidebarblock>.content>:last-child>:last-child,.sidebarblock>.content .olist>ol>li:last-child>:last-child,.sidebarblock>.content .ulist>ul>li:last-child>:last-child,.sidebarblock>.content .qlist>ol>li:last-child>:last-child{margin-bottom:0}
.literalblock pre,.listingblock pre:not(.highlight),.listingblock pre[class="highlight"],.listingblock pre[class^="highlight "],.listingblock pre.CodeRay,.listingblock pre.prettyprint{background:#f7f7f8}
.sidebarblock .literalblock pre,.sidebarblock .listingblock pre:not(.highlight),.sidebarblock .listingblock pre[class="highlight"],.sidebarblock .listingblock pre[class^="highlight "],.sidebarblock .listingblock pre.CodeRay,.sidebarblock .listingblock pre.prettyprint{background:#f2f1f1}
.literalblock pre,.literalblock pre[class],.listingblock pre,.listingblock pre[class]{-webkit-border-radius:4px;border-radius:4px;word-wrap:break-word;padding:1em;font-size:.8125em}
.literalblock pre.nowrap,.literalblock pre[class].nowrap,.listingblock pre.nowrap,.listingblock pre[class].nowrap{overflow-x:auto;white-space:pre;word-wrap:normal}
@media only screen and (min-width:768px){.literalblock pre,.literalblock pre[class],.listingblock pre,.listingblock pre[class]{font-size:.90625em}}
@media only screen and (min-width:1280px){.literalblock pre,.literalblock pre[class],.listingblock pre,.listingblock pre[class]{font-size:1em}}
.literalblock.output pre{color:#f7f7f8;background-color:rgba(0,0,0,.9)}
.listingblock pre.highlightjs{padding:0}
.listingblock pre.highlightjs>code{padding:1em;-webkit-border-radius:4px;border-radius:4px}
.listingblock pre.prettyprint{border-width:0}
.listingblock>.content{position:relative}
.listingblock code[data-lang]:before{display:none;content:attr(data-lang);position:absolute;font-size:.75em;top:.425rem;right:.5rem;line-height:1;text-transform:uppercase;color:#999}
.listingblock:hover code[data-lang]:before{display:block}
.listingblock.terminal pre .command:before{content:attr(data-prompt);padding-right:.5em;color:#999}
.listingblock.terminal pre .command:not([data-prompt]):before{content:"$"}
table.pyhltable{border-collapse:separate;border:0;margin-bottom:0;background:none}
table.pyhltable td{vertical-align:top;padding-top:0;padding-bottom:0;line-height:1.45}
table.pyhltable td.code{padding-left:.75em;padding-right:0}
pre.pygments .lineno,table.pyhltable td:not(.code){color:#999;padding-left:0;padding-right:.5em;border-right:1px solid #ddddd8}
pre.pygments .lineno{display:inline-block;margin-right:.25em}
table.pyhltable .linenodiv{background:none!important;padding-right:0!important}
.quoteblock{margin:0 1em 1.25em 1.5em;display:table}
.quoteblock>.title{margin-left:-1.5em;margin-bottom:.75em}
.quoteblock blockquote,.quoteblock blockquote p{color:rgba(0,0,0,.85);font-size:1.15rem;line-height:1.75;word-spacing:.1em;letter-spacing:0;font-style:italic;text-align:justify}
.quoteblock blockquote{margin:0;padding:0;border:0}
.quoteblock blockquote:before{content:"\201c";float:left;font-size:2.75em;font-weight:bold;line-height:.6em;margin-left:-.6em;color:#7a2518;text-shadow:0 1px 2px rgba(0,0,0,.1)}
.quoteblock blockquote>.paragraph:last-child p{margin-bottom:0}
.quoteblock .attribution{margin-top:.5em;margin-right:.5ex;text-align:right}
.quoteblock .quoteblock{margin-left:0;margin-right:0;padding:.5em 0;border-left:3px solid rgba(0,0,0,.6)}
.quoteblock .quoteblock blockquote{padding:0 0 0 .75em}
.quoteblock .quoteblock blockquote:before{display:none}
.verseblock{margin:0 1em 1.25em 1em}
.verseblock pre{font-family:"Open Sans","DejaVu Sans",sans;font-size:1.15rem;color:rgba(0,0,0,.85);font-weight:300;text-rendering:optimizeLegibility}
.verseblock pre strong{font-weight:400}
.verseblock .attribution{margin-top:1.25rem;margin-left:.5ex}
.quoteblock .attribution,.verseblock .attribution{font-size:.9375em;line-height:1.45;font-style:italic}
.quoteblock .attribution br,.verseblock .attribution br{display:none}
.quoteblock .attribution cite,.verseblock .attribution cite{display:block;letter-spacing:-.025em;color:rgba(0,0,0,.6)}
.quoteblock.abstract{margin:0 0 1.25em 0;display:block}
.quoteblock.abstract blockquote,.quoteblock.abstract blockquote p{text-align:left;word-spacing:0}
.quoteblock.abstract blockquote:before,.quoteblock.abstract blockquote p:first-of-type:before{display:none}
table.tableblock{max-width:100%;border-collapse:separate}
table.tableblock td>.paragraph:last-child p>p:last-child,table.tableblock th>p:last-child,table.tableblock td>p:last-child{margin-bottom:0}
table.tableblock,th.tableblock,td.tableblock{border:0 solid #dedede}
table.grid-all th.tableblock,table.grid-all td.tableblock{border-width:0 1px 1px 0}
table.grid-all tfoot>tr>th.tableblock,table.grid-all tfoot>tr>td.tableblock{border-width:1px 1px 0 0}
table.grid-cols th.tableblock,table.grid-cols td.tableblock{border-width:0 1px 0 0}
table.grid-all *>tr>.tableblock:last-child,table.grid-cols *>tr>.tableblock:last-child{border-right-width:0}
table.grid-rows th.tableblock,table.grid-rows td.tableblock{border-width:0 0 1px 0}
table.grid-all tbody>tr:last-child>th.tableblock,table.grid-all tbody>tr:last-child>td.tableblock,table.grid-all thead:last-child>tr>th.tableblock,table.grid-rows tbody>tr:last-child>th.tableblock,table.grid-rows tbody>tr:last-child>td.tableblock,table.grid-rows thead:last-child>tr>th.tableblock{border-bottom-width:0}
table.grid-rows tfoot>tr>th.tableblock,table.grid-rows tfoot>tr>td.tableblock{border-width:1px 0 0 0}
table.frame-all{border-width:1px}
table.frame-sides{border-width:0 1px}
table.frame-topbot{border-width:1px 0}
th.halign-left,td.halign-left{text-align:left}
th.halign-right,td.halign-right{text-align:right}
th.halign-center,td.halign-center{text-align:center}
th.valign-top,td.valign-top{vertical-align:top}
th.valign-bottom,td.valign-bottom{vertical-align:bottom}
th.valign-middle,td.valign-middle{vertical-align:middle}
table thead th,table tfoot th{font-weight:bold}
tbody tr th{display:table-cell;line-height:1.6;background:#f7f8f7}
tbody tr th,tbody tr th p,tfoot tr th,tfoot tr th p{color:rgba(0,0,0,.8);font-weight:bold}
p.tableblock>code:only-child{background:none;padding:0}
p.tableblock{font-size:1em}
td>div.verse{white-space:pre}
ol{margin-left:1.75em}
ul li ol{margin-left:1.5em}
dl dd{margin-left:1.125em}
dl dd:last-child,dl dd:last-child>:last-child{margin-bottom:0}
ol>li p,ul>li p,ul dd,ol dd,.olist .olist,.ulist .ulist,.ulist .olist,.olist .ulist{margin-bottom:.625em}
ul.unstyled,ol.unnumbered,ul.checklist,ul.none{list-style-type:none}
ul.unstyled,ol.unnumbered,ul.checklist{margin-left:.625em}
ul.checklist li>p:first-child>.fa-square-o:first-child,ul.checklist li>p:first-child>.fa-check-square-o:first-child{width:1em;font-size:.85em}
ul.checklist li>p:first-child>input[type="checkbox"]:first-child{width:1em;position:relative;top:1px}
ul.inline{margin:0 auto .625em auto;margin-left:-1.375em;margin-right:0;padding:0;list-style:none;overflow:hidden}
ul.inline>li{list-style:none;float:left;margin-left:1.375em;display:block}
ul.inline>li>*{display:block}
.unstyled dl dt{font-weight:400;font-style:normal}
ol.arabic{list-style-type:decimal}
ol.decimal{list-style-type:decimal-leading-zero}
ol.loweralpha{list-style-type:lower-alpha}
ol.upperalpha{list-style-type:upper-alpha}
ol.lowerroman{list-style-type:lower-roman}
ol.upperroman{list-style-type:upper-roman}
ol.lowergreek{list-style-type:lower-greek}
.hdlist>table,.colist>table{border:0;background:none}
.hdlist>table>tbody>tr,.colist>table>tbody>tr{background:none}
td.hdlist1,td.hdlist2{vertical-align:top;padding:0 .625em}
td.hdlist1{font-weight:bold;padding-bottom:1.25em}
.literalblock+.colist,.listingblock+.colist{margin-top:-.5em}
.colist>table tr>td:first-of-type{padding:0 .75em;line-height:1}
.colist>table tr>td:last-of-type{padding:.25em 0}
.thumb,.th{line-height:0;display:inline-block;border:solid 4px #fff;-webkit-box-shadow:0 0 0 1px #ddd;box-shadow:0 0 0 1px #ddd}
.imageblock.left,.imageblock[style*="float: left"]{margin:.25em .625em 1.25em 0}
.imageblock.right,.imageblock[style*="float: right"]{margin:.25em 0 1.25em .625em}
.imageblock>.title{margin-bottom:0}
.imageblock.thumb,.imageblock.th{border-width:6px}
.imageblock.thumb>.title,.imageblock.th>.title{padding:0 .125em}
.image.left,.image.right{margin-top:.25em;margin-bottom:.25em;display:inline-block;line-height:0}
.image.left{margin-right:.625em}
.image.right{margin-left:.625em}
a.image{text-decoration:none;display:inline-block}
a.image object{pointer-events:none}
sup.footnote,sup.footnoteref{font-size:.875em;position:static;vertical-align:super}
sup.footnote a,sup.footnoteref a{text-decoration:none}
sup.footnote a:active,sup.footnoteref a:active{text-decoration:underline}
#footnotes{padding-top:.75em;padding-bottom:.75em;margin-bottom:.625em}
#footnotes hr{width:20%;min-width:6.25em;margin:-.25em 0 .75em 0;border-width:1px 0 0 0}
#footnotes .footnote{padding:0 .375em 0 .225em;line-height:1.3334;font-size:.875em;margin-left:1.2em;text-indent:-1.05em;margin-bottom:.2em}
#footnotes .footnote a:first-of-type{font-weight:bold;text-decoration:none}
#footnotes .footnote:last-of-type{margin-bottom:0}
#content #footnotes{margin-top:-.625em;margin-bottom:0;padding:.75em 0}
.gist .file-data>table{border:0;background:#fff;width:100%;margin-bottom:0}
.gist .file-data>table td.line-data{width:99%}
div.unbreakable{page-break-inside:avoid}
.big{font-size:larger}
.small{font-size:smaller}
.underline{text-decoration:underline}
.overline{text-decoration:overline}
.line-through{text-decoration:line-through}
.aqua{color:#00bfbf}
.aqua-background{background-color:#00fafa}
.black{color:#000}
.black-background{background-color:#000}
.blue{color:#0000bf}
.blue-background{background-color:#0000fa}
.fuchsia{color:#bf00bf}
.fuchsia-background{background-color:#fa00fa}
.gray{color:#606060}
.gray-background{background-color:#7d7d7d}
.green{color:#006000}
.green-background{background-color:#007d00}
.lime{color:#00bf00}
.lime-background{background-color:#00fa00}
.maroon{color:#600000}
.maroon-background{background-color:#7d0000}
.navy{color:#000060}
.navy-background{background-color:#00007d}
.olive{color:#606000}
.olive-background{background-color:#7d7d00}
.purple{color:#600060}
.purple-background{background-color:#7d007d}
.red{color:#bf0000}
.red-background{background-color:#fa0000}
.silver{color:#909090}
.silver-background{background-color:#bcbcbc}
.teal{color:#006060}
.teal-background{background-color:#007d7d}
.white{color:#bfbfbf}
.white-background{background-color:#fafafa}
.yellow{color:#bfbf00}
.yellow-background{background-color:#fafa00}
span.icon>.fa{cursor:default}
.admonitionblock td.icon [class^="fa icon-"]{font-size:2.5em;text-shadow:1px 1px 2px rgba(0,0,0,.5);cursor:default}
.admonitionblock td.icon .icon-note:before{content:"\f05a";color:#19407c}
.admonitionblock td.icon .icon-tip:before{content:"\f0eb";text-shadow:1px 1px 2px rgba(155,155,0,.8);color:#111}
.admonitionblock td.icon .icon-warning:before{content:"\f071";color:#bf6900}
.admonitionblock td.icon .icon-caution:before{content:"\f06d";color:#bf3400}
.admonitionblock td.icon .icon-important:before{content:"\f06a";color:#bf0000}
.conum[data-value]{display:inline-block;color:#fff!important;background-color:rgba(0,0,0,.8);-webkit-border-radius:100px;border-radius:100px;text-align:center;font-size:.75em;width:1.67em;height:1.67em;line-height:1.67em;font-family:"Open Sans","DejaVu Sans",sans-serif;font-style:normal;font-weight:bold}
.conum[data-value] *{color:#fff!important}
.conum[data-value]+b{display:none}
.conum[data-value]:after{content:attr(data-value)}
pre .conum[data-value]{position:relative;top:-.125em}
b.conum *{color:inherit!important}
.conum:not([data-value]):empty{display:none}
dt,th.tableblock,td.content,div.footnote{text-rendering:optimizeLegibility}
h1,h2,p,td.content,span.alt{letter-spacing:-.01em}
p strong,td.content strong,div.footnote strong{letter-spacing:-.005em}
p,blockquote,dt,td.content,span.alt{font-size:1.0625rem}
p{margin-bottom:1.25rem}
.sidebarblock p,.sidebarblock dt,.sidebarblock td.content,p.tableblock{font-size:1em}
.exampleblock>.content{background-color:#fffef7;border-color:#e0e0dc;-webkit-box-shadow:0 1px 4px #e0e0dc;box-shadow:0 1px 4px #e0e0dc}
.print-only{display:none!important}
@media print{@page{margin:1.25cm .75cm}
*{-webkit-box-shadow:none!important;box-shadow:none!important;text-shadow:none!important}
a{color:inherit!important;text-decoration:underline!important}
a.bare,a[href^="#"],a[href^="mailto:"]{text-decoration:none!important}
a[href^="http:"]:not(.bare):after,a[href^="https:"]:not(.bare):after{content:"(" attr(href) ")";display:inline-block;font-size:.875em;padding-left:.25em}
abbr[title]:after{content:" (" attr(title) ")"}
pre,blockquote,tr,img,object,svg{page-break-inside:avoid}
thead{display:table-header-group}
svg{max-width:100%}
p,blockquote,dt,td.content{font-size:1em;orphans:3;widows:3}
h2,h3,#toctitle,.sidebarblock>.content>.title{page-break-after:avoid}
#toc,.sidebarblock,.exampleblock>.content{background:none!important}
#toc{border-bottom:1px solid #ddddd8!important;padding-bottom:0!important}
.sect1{padding-bottom:0!important}
.sect1+.sect1{border:0!important}
#header>h1:first-child{margin-top:1.25rem}
body.book #header{text-align:center}
body.book #header>h1:first-child{border:0!important;margin:2.5em 0 1em 0}
body.book #header .details{border:0!important;display:block;padding:0!important}
body.book #header .details span:first-child{margin-left:0!important}
body.book #header .details br{display:block}
body.book #header .details br+span:before{content:none!important}
body.book #toc{border:0!important;text-align:left!important;padding:0!important;margin:0!important}
body.book #toc,body.book #preamble,body.book h1.sect0,body.book .sect1>h2{page-break-before:always}
.listingblock code[data-lang]:before{display:block}
#footer{background:none!important;padding:0 .9375em}
#footer-text{color:rgba(0,0,0,.6)!important;font-size:.9em}
.hide-on-print{display:none!important}
.print-only{display:block!important}
.hide-for-print{display:none!important}
.show-for-print{display:inherit!important}}
</style>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.6.3/css/font-awesome.min.css">
</head>
<body class="book">
<div id="header">
<h1>JDK</h1>
<div id="toc" class="toc">
<div id="toctitle">JDK</div>
<ul class="sectlevel1">
<li><a href="#_源码">1. 源码</a>
<ul class="sectlevel2">
<li><a href="#_java_中的数据类型">1.1. Java 中的数据类型</a></li>
<li><a href="#_boolean">1.2. Boolean</a></li>
<li><a href="#_byte">1.3. Byte</a></li>
<li><a href="#_boolean_2">1.4. Boolean</a></li>
<li><a href="#_character">1.5. Character</a></li>
<li><a href="#_double">1.6. Double</a></li>
<li><a href="#_float">1.7. Float</a></li>
<li><a href="#_integer">1.8. Integer</a></li>
<li><a href="#_long">1.9. Long</a></li>
<li><a href="#_short">1.10. Short</a></li>
<li><a href="#_string">1.11. String</a></li>
<li><a href="#_jvm">1.12. JVM</a></li>
<li><a href="#_java_注解">1.13. Java 注解</a></li>
<li><a href="#_stream_流系列">1.14. Stream 流系列</a></li>
<li><a href="#_lambda">1.15. Lambda</a></li>
</ul>
</li>
<li><a href="#_分析下lambda表达式创建条件">2. 分析下Lambda表达式创建条件</a>
<ul class="sectlevel2">
<li><a href="#_日期">2.1. 日期</a></li>
<li><a href="#_jdk1_8之前">2.2. jdk1.8之前</a></li>
</ul>
</li>
<li><a href="#_jdk1_8之后">3. jdk1.8之后</a></li>
</ul>
</div>
</div>
<div id="content">
<div class="sect1">
<h2 id="_源码">1. 源码</h2>
<div class="sectionbody">
<div class="sect2">
<h3 id="_java_中的数据类型">1.1. Java 中的数据类型</h3>
<div class="paragraph">
<p>Java语言提供了八种基本类型。六种数字类型（四个整数型，两个浮点型），一种字符类型，还有一种布尔型。</p>
</div>
<div class="sect3">
<h4 id="_字符类型">字符类型</h4>
<div class="paragraph">
<p>char:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>char类型是一个单一的 16 位 Unicode 字符；</p>
</li>
<li>
<p>最小值是 <strong>000</strong>（即为 0）；</p>
</li>
<li>
<p>最大值是 <strong>*</strong>（即为65535）；</p>
</li>
<li>
<p>char 数据类型可以储存任何字符；</p>
</li>
<li>
<p>使用单引号，例子：char letter = &#8216;A&#8217;;。</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>扩展知识：编码以及编码规范</p>
</div>
</div>
<div class="sect3">
<h4 id="_boolean_类型">boolean 类型</h4>
<div class="paragraph">
<p>boolean:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>boolean数据类型表示一位的信息；</p>
</li>
<li>
<p>只有两个取值：true 和 false；</p>
</li>
<li>
<p>这种类型只作为一种标志来记录 true/false 情况；</p>
</li>
<li>
<p>默认值是 <strong>false</strong>；</p>
</li>
</ul>
</div>
</div>
<div class="sect3">
<h4 id="_数字类型">数字类型</h4>
<div class="paragraph">
<p><strong>byte：</strong></p>
</div>
<div class="ulist">
<ul>
<li>
<p>byte 数据类型是8位、有符号的，以二进制补码表示的整数；</p>
</li>
<li>
<p>最小值是 <strong>-128（-2^7）</strong>；</p>
</li>
<li>
<p>最大值是 <strong>127（2^7-1）</strong>；</p>
</li>
<li>
<p>默认值是 <strong>0</strong>；</p>
</li>
<li>
<p>byte 类型用在大型数组中节约空间，主要代替整数，因为 byte
变量占用的空间只有 int 类型的四分之一；</p>
</li>
<li>
<p>例子：byte a = 100，byte b = -50。</p>
</li>
</ul>
</div>
<div class="paragraph">
<p><strong>short：</strong></p>
</div>
<div class="ulist">
<ul>
<li>
<p>short 数据类型是 16 位、有符号的以二进制补码表示的整数</p>
</li>
<li>
<p>最小值是 <strong>-32768（-2^15）</strong>；</p>
</li>
<li>
<p>最大值是 <strong>32767（2^15 - 1）</strong>；</p>
</li>
<li>
<p>Short 数据类型也可以像 byte
那样节省空间。一个short变量是int型变量所占空间的二分之一；</p>
</li>
<li>
<p>默认值是 <strong>0</strong>；</p>
</li>
<li>
<p>例子：short s = 1000，short r = -20000。</p>
</li>
</ul>
</div>
<div class="paragraph">
<p><strong>int：</strong></p>
</div>
<div class="ulist">
<ul>
<li>
<p>int 数据类型是32位、有符号的以二进制补码表示的整数；</p>
</li>
<li>
<p>最小值是 <strong>-2,147,483,648（-2^31）</strong>；</p>
</li>
<li>
<p>最大值是 <strong>2,147,483,647（2^31 - 1）</strong>；</p>
</li>
<li>
<p>一般地整型变量默认为 int 类型；</p>
</li>
<li>
<p>默认值是 <strong>0</strong> ；</p>
</li>
<li>
<p>例子：int a = 100000, int b = -200000。</p>
</li>
</ul>
</div>
<div class="paragraph">
<p><strong>long：</strong></p>
</div>
<div class="ulist">
<ul>
<li>
<p>long 数据类型是 64 位、有符号的以二进制补码表示的整数；</p>
</li>
<li>
<p>最小值是 <strong>-9,223,372,036,854,775,808（-2^63）</strong>；</p>
</li>
<li>
<p>最大值是 <strong>9,223,372,036,854,775,807（2^63 -1）</strong>；</p>
</li>
<li>
<p>这种类型主要使用在需要比较大整数的系统上；</p>
</li>
<li>
<p>默认值是 <strong>0L</strong>；</p>
</li>
<li>
<p>例子： long a = 100000L，Long b = -200000L。
"`L`"理论上不分大小写，但是若写成”l”容易与数字”1”混淆，不容易分辩。所以最好大写。</p>
</li>
</ul>
</div>
<div class="paragraph">
<p><strong>float：</strong></p>
</div>
<div class="ulist">
<ul>
<li>
<p>float 数据类型是单精度、32位、符合IEEE 754标准的浮点数；</p>
</li>
<li>
<p>float 在储存大型浮点数组的时候可节省内存空间；</p>
</li>
<li>
<p>默认值是 <strong>0.0f</strong>；</p>
</li>
<li>
<p>浮点数不能用来表示精确的值，如货币；</p>
</li>
<li>
<p>例子：float f1 = 234.5f。</p>
</li>
</ul>
</div>
<div class="paragraph">
<p><strong>double：</strong></p>
</div>
<div class="ulist">
<ul>
<li>
<p>double 数据类型是双精度、64 位、符合IEEE 754标准的浮点数；</p>
</li>
<li>
<p>浮点数的默认类型为double类型；</p>
</li>
<li>
<p>double类型同样不能表示精确的值，如货币；</p>
</li>
<li>
<p>默认值是 <strong>0.0d</strong>；</p>
</li>
<li>
<p>例子：double d1 = 123.4。</p>
</li>
</ul>
</div>
</div>
<div class="sect3">
<h4 id="_关于范围">关于范围</h4>
<div class="paragraph">
<p>1个字节 = 8个bit，每个位只能是0和1这2中可能，最高位是符号位。</p>
</div>
<div class="paragraph">
<p>byte，1个字节，8位，除了最高位符号位，每个位能存0或1，所以有2^7中可能，可以存128个数，但是是从0开始的，因此需要减1，所有能表示的数为0-127。负数就没有0了，同样能存128个数，所有负数的范围是-1
至 -128，因此 byte的范围为 -2^7 ~ 2^7 -1</p>
</div>
<div class="paragraph">
<p>short，2个字节，16位，同理，范围是 <strong>-2^15</strong> ~ <strong>2^15 - 1</strong></p>
</div>
<div class="paragraph">
<p>int， 4个字节，32位，同理，范围是 <strong>-2<sup>31<strong>~</strong>2</sup>31 - 1</strong></p>
</div>
<div class="paragraph">
<p>long， 8个字节，64位，同理，范围是 <strong>-2^63</strong> ~ <strong>2^63 -1</strong></p>
</div>
<div class="paragraph">
<p>float 和 double 不适用。</p>
</div>
<div class="paragraph">
<p>参考：https://www.runoob.com/java/java-basic-datatypes.html</p>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_boolean">1.2. Boolean</h3>
<div class="paragraph">
<p><strong>提供了 2 个重要的静态对象</strong></p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java" data-lang="java">public static final Boolean TRUE = new Boolean(true);

public static final Boolean FALSE = new Boolean(false);</code></pre>
</div>
</div>
<div class="paragraph">
<p>作用：缓存，提升性能。</p>
</div>
<div class="paragraph">
<p><strong>提供 2 个构造器创建 Boolean 对象</strong></p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java" data-lang="java">public Boolean(boolean value) {
    this.value = value;
}

public Boolean(String s) {
    this(parseBoolean(s));
}</code></pre>
</div>
</div>
<div class="paragraph">
<p><strong>提供 2 个静态方法创建 Boolean 对象</strong></p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java" data-lang="java">public static Boolean valueOf(boolean b) {
    return (b ? TRUE : FALSE);
}

public static Boolean valueOf(String s) {
    return parseBoolean(s) ? TRUE : FALSE;
}</code></pre>
</div>
</div>
<div class="paragraph">
<p><strong>提供了一个字符串转 Boolean 对象方法</strong></p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java" data-lang="java">public static boolean parseBoolean(String s) {
    return ((s != null) &amp;&amp; s.equalsIgnoreCase("true"));
}</code></pre>
</div>
</div>
<div class="paragraph">
<p><strong>提供了 Boolean 值转字符串的方法</strong></p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java" data-lang="java">public static String toString(boolean b) {
    return b ? "true" : "false";
}

public String toString() {
    return value ? "true" : "false";
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>*重写了 hashcode *</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java" data-lang="java">@Override
public int hashCode() {
    return Boolean.hashCode(value);
}

public static int hashCode(boolean value) {
    return value ? 1231 : 1237;
}</code></pre>
</div>
</div>
<div class="paragraph">
<p><strong>equals</strong></p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java" data-lang="java">public boolean equals(Object obj) {
    if (obj instanceof Boolean) {
        return value == ((Boolean)obj).booleanValue();
    }
    return false;
}</code></pre>
</div>
</div>
<div class="paragraph">
<p><strong>比较</strong></p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java" data-lang="java">public int compareTo(Boolean b) {
    return compare(this.value, b.value);
}

public static int compare(boolean x, boolean y) {
    return (x == y) ? 0 : (x ? 1 : -1);
}</code></pre>
</div>
</div>
<div class="paragraph">
<p><strong>逻辑比较，1.8版本开始</strong></p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java" data-lang="java">public static boolean logicalAnd(boolean a, boolean b) {
    return a &amp;&amp; b;
}

public static boolean logicalOr(boolean a, boolean b) {
    return a || b;
}

public static boolean logicalXor(boolean a, boolean b) {
    return a ^ b;
}</code></pre>
</div>
</div>
<div class="paragraph">
<p><strong>总结</strong></p>
</div>
<div class="olist arabic">
<ol class="arabic">
<li>
<p>提供了字符串和boolean值的相互转换方法</p>
</li>
<li>
<p>使用valueOf而不是构造器创建Boolean对象，提高性能</p>
</li>
<li>
<p>重写了hashcod函数</p>
</li>
<li>
<p>compare比较</p>
</li>
<li>
<p>逻辑判断，1.8之后。</p>
</li>
</ol>
</div>
</div>
<div class="sect2">
<h3 id="_byte">1.3. Byte</h3>
<div class="paragraph">
<p><strong>定义了取值范围</strong></p>
</div>
<div class="literalblock">
<div class="content">
<pre>public static final byte  MIN_VALUE = -128;

public static final byte  MAX_VALUE = 127;</pre>
</div>
</div>
<div class="paragraph">
<p><strong>调用 Integer 的方法进行 Byte 转 String</strong></p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java" data-lang="java">public static String toString(byte b) {
    return Integer.toString((int)b, 10);
}</code></pre>
</div>
</div>
<div class="paragraph">
<p><strong>定义了内部静态缓存类，提高性能</strong></p>
</div>
<div class="literalblock">
<div class="content">
<pre>private static class ByteCache {
    private ByteCache(){}

    static final Byte cache[] = new Byte[-(-128) + 127 + 1];

    static {
        for(int i = 0; i &lt; cache.length; i++)
            cache[i] = new Byte((byte)(i - 128));
    }
}</pre>
</div>
</div>
<div class="paragraph">
<p><strong>byte 转 Byte 对象</strong></p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java" data-lang="java">public static Byte valueOf(byte b) {
    final int offset = 128;
    return ByteCache.cache[(int)b + offset];
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>取缓存里面的对象。</p>
</div>
<div class="paragraph">
<p>*字符串转 byte *</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java" data-lang="java">public static byte parseByte(String s, int radix)
    throws NumberFormatException {
    int i = Integer.parseInt(s, radix);
    if (i &lt; MIN_VALUE || i &gt; MAX_VALUE)
        throw new NumberFormatException(
            "Value out of range. Value:\"" + s + "\" Radix:" + radix);
    return (byte)i;
}

public static byte parseByte(String s) throws NumberFormatException {
    return parseByte(s, 10);
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>底层实现还是使用 Integer 对象进行解析。</p>
</div>
<div class="paragraph">
<p><strong>字符串转 Byte 对象</strong></p>
</div>
<div class="literalblock">
<div class="content">
<pre>public static Byte valueOf(String s, int radix)
    throws NumberFormatException {
    return valueOf(parseByte(s, radix));
}

public static Byte valueOf(String s) throws NumberFormatException {
    return valueOf(s, 10);
}</pre>
</div>
</div>
<div class="paragraph">
<p>先通过 Integer，将字符串转 为byte 值，再从缓存中取出对应值的 Byte 对象。</p>
</div>
<div class="paragraph">
<p><strong>解析带符号的进制数</strong></p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java" data-lang="java">public static Byte decode(String nm) throws NumberFormatException {
    int i = Integer.decode(nm);
    if (i &lt; MIN_VALUE || i &gt; MAX_VALUE)
        throw new NumberFormatException(
                "Value " + i + " out of range from input " + nm);
    return valueOf((byte)i);
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>底层也是采用 Integer 提供的方法</p>
</div>
<div class="paragraph">
<p><strong>提供2个构造器创建Byte对象</strong></p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java" data-lang="java">public Byte(byte value) {
    this.value = value;
}

public Byte(String s) throws NumberFormatException {
    this.value = parseByte(s, 10);
}</code></pre>
</div>
</div>
<div class="paragraph">
<p><strong>数值转换</strong></p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java" data-lang="java">public byte byteValue() {
    return value;
}

public short shortValue() {
    return (short)value;
}

public int intValue() {
    return (int)value;
}

public long longValue() {
    return (long)value;
}

public float floatValue() {
    return (float)value;
}

public double doubleValue() {
    return (double)value;
}

public String toString() {
    return Integer.toString((int)value);
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>实现了 Number 类，需要实现这些方法。toString 除外。</p>
</div>
<div class="paragraph">
<p><strong>hashCode、equals、compare函数</strong></p>
</div>
<div class="literalblock">
<div class="content">
<pre>@Override
public int hashCode() {
    return Byte.hashCode(value);
}

public static int hashCode(byte value) {
    return (int)value;
}

public boolean equals(Object obj) {
    if (obj instanceof Byte) {
        return value == ((Byte)obj).byteValue();
    }
    return false;
}

public int compareTo(Byte anotherByte) {
    return compare(this.value, anotherByte.value);
}
public static int compare(byte x, byte y) {
    return x - y;
}</pre>
</div>
</div>
<div class="paragraph">
<p><strong>转无符号 int 和 long 数方法</strong></p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java" data-lang="java">public static int toUnsignedInt(byte x) {
    return ((int) x) &amp; 0xff;
}
public static long toUnsignedLong(byte x) {
    return ((long) x) &amp; 0xffL;
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>不知用处，暂时忽略。</p>
</div>
</div>
<div class="sect2">
<h3 id="_boolean_2">1.4. Boolean</h3>
<div class="paragraph">
<p><strong>提供了 2 个重要的静态对象</strong></p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java" data-lang="java">public static final Boolean TRUE = new Boolean(true);

public static final Boolean FALSE = new Boolean(false);</code></pre>
</div>
</div>
<div class="paragraph">
<p>作用：缓存，提升性能。</p>
</div>
<div class="paragraph">
<p><strong>提供 2 个构造器创建 Boolean 对象</strong></p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java" data-lang="java">public Boolean(boolean value) {
    this.value = value;
}

public Boolean(String s) {
    this(parseBoolean(s));
}</code></pre>
</div>
</div>
<div class="paragraph">
<p><strong>提供 2 个静态方法创建 Boolean 对象</strong></p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java" data-lang="java">public static Boolean valueOf(boolean b) {
    return (b ? TRUE : FALSE);
}

public static Boolean valueOf(String s) {
    return parseBoolean(s) ? TRUE : FALSE;
}</code></pre>
</div>
</div>
<div class="paragraph">
<p><strong>提供了一个字符串转 Boolean 对象方法</strong></p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java" data-lang="java">public static boolean parseBoolean(String s) {
    return ((s != null) &amp;&amp; s.equalsIgnoreCase("true"));
}</code></pre>
</div>
</div>
<div class="paragraph">
<p><strong>提供了 Boolean 值转字符串的方法</strong></p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java" data-lang="java">public static String toString(boolean b) {
    return b ? "true" : "false";
}

public String toString() {
    return value ? "true" : "false";
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>*重写了 hashcode *</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java" data-lang="java">@Override
public int hashCode() {
    return Boolean.hashCode(value);
}

public static int hashCode(boolean value) {
    return value ? 1231 : 1237;
}</code></pre>
</div>
</div>
<div class="paragraph">
<p><strong>equals</strong></p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java" data-lang="java">public boolean equals(Object obj) {
    if (obj instanceof Boolean) {
        return value == ((Boolean)obj).booleanValue();
    }
    return false;
}</code></pre>
</div>
</div>
<div class="paragraph">
<p><strong>比较</strong></p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java" data-lang="java">public int compareTo(Boolean b) {
    return compare(this.value, b.value);
}

public static int compare(boolean x, boolean y) {
    return (x == y) ? 0 : (x ? 1 : -1);
}</code></pre>
</div>
</div>
<div class="paragraph">
<p><strong>逻辑比较，1.8版本开始</strong></p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java" data-lang="java">public static boolean logicalAnd(boolean a, boolean b) {
    return a &amp;&amp; b;
}

public static boolean logicalOr(boolean a, boolean b) {
    return a || b;
}

public static boolean logicalXor(boolean a, boolean b) {
    return a ^ b;
}</code></pre>
</div>
</div>
<div class="paragraph">
<p><strong>总结</strong></p>
</div>
<div class="olist arabic">
<ol class="arabic">
<li>
<p>提供了字符串和boolean值的相互转换方法</p>
</li>
<li>
<p>使用valueOf而不是构造器创建Boolean对象，提高性能</p>
</li>
<li>
<p>重写了hashcod函数</p>
</li>
<li>
<p>compare比较</p>
</li>
<li>
<p>逻辑判断，1.8之后。</p>
</li>
</ol>
</div>
</div>
<div class="sect2">
<h3 id="_character">1.5. Character</h3>
<div class="paragraph">
<p>字符，涉及到计算机的组成原理，编码等知识，这里记录下理解的概念。</p>
</div>
<div class="paragraph">
<p><strong>计算机常识</strong></p>
</div>
<div class="olist arabic">
<ol class="arabic">
<li>
<p>计算机只能识别 0 和 1</p>
</li>
<li>
<p>0 和 1，能表示 2 进制数</p>
</li>
<li>
<p>2 进制数能转为人类可直观阅读的 10进制数</p>
</li>
<li>
<p>人为规定每个 10 进制数字代表什么字符，就成为了编码（映射）。</p>
</li>
<li>
<p>规定不同，导致每个数字代表的字符不同，就形成了不同的编码规范，例如GBK（中国规范）、Unicode（国标）、其他国家也有自己字符的编码。</p>
</li>
<li>
<p>unicode是为了统一所有的字符而产生的。java默认采用的编码规范。</p>
</li>
</ol>
</div>
<div class="paragraph">
<p><strong>为什么会出现乱码</strong></p>
</div>
<div class="paragraph">
<p><strong>编码和解码方式不一致，就会导致乱码</strong>。比如通过 GBK 进行编码，数字 1 可能代表一个汉字，编码后为 2 进制数，但是如果用其他编码进行解析，例如 unicode，这个 2 进制数，代表的可能是另外一个字符，显示出来就不是最初的哪个汉字，当然如果没有这个数字对应的字符，就会出现乱码。</p>
</div>
<div class="paragraph">
<p><strong>Unicode 基本知识</strong></p>
</div>
<div class="olist arabic">
<ol class="arabic">
<li>
<p>Unicode又称为统一码、万国码、单一码，是国际组织制定的旨在容纳全球所有字符的编码方案，包括字符集、编码方案等，它为每种语言中的每个字符设定了统一且唯一的二进制编码，以满足跨语言、跨平台的要求。</p>
</li>
<li>
<p>Unicode 字符集被分成多个区，Unicode 将“区”称为平面。Unicode 字符集被划分为
17 个平面(即，17 个区，编号为 0-16 )</p>
</li>
<li>
<p>每个平面有 216 = 65536 个代码点，每个代码点都可以代表一个字符。</p>
</li>
<li>
<p>并不是每个码点就一定对应有一个字符，因为，目前 Unicode 字符集中有很多码点都还未被使用。</p>
</li>
<li>
<p>17个平面又分为以下两类平面。<strong>基本多文种平面</strong> ( Basic Multilingual
Plane，BMP，或称为基本多语言平面、<strong>基本平面</strong>、第零平面、平面 0 )，<strong>辅助平面(或称为增补平面)</strong>，每类平面都有各自划分含义，这里不深究。</p>
</li>
<li>
<p>增补字符使用两个 char 型变量来表示</p>
</li>
<li>
<p>2 类平面不做深入研究，只需要知道，javaCharacter 类中有很多方法来检测码点属于哪个平面。</p>
</li>
<li>
<p><strong>码点空间</strong>，从 0 到上限值之间的范围称为码点空间，例如 Unicode 基本平面的空间为
0 ~ 65535</p>
</li>
<li>
<p><strong>代码点(Code
Point，简称码点)和码点值</strong>，codePoint 在 Character 类中常出现。<strong>码点</strong>是指码点空间中的一个位置，该位置所代表的数值就是码点值</p>
</li>
</ol>
</div>
<div class="paragraph">
<p><strong>Character.java 源码解析</strong></p>
</div>
<div class="paragraph">
<p>（1）很多静态常量</p>
</div>
<div class="paragraph">
<p>都是一些 Unicode 规范的类别分类，知道即可。</p>
</div>
<div class="paragraph">
<p>（2）很多判断方法</p>
</div>
<div class="paragraph">
<p>多数用于判断码点的类型、属于哪个平面、是否是某一个类型。</p>
</div>
<div class="paragraph">
<p>（3）一些常规的方法</p>
</div>
<div class="paragraph">
<p>比较，toString、hashCode等</p>
</div>
<div class="paragraph">
<p>（4）重要的内部类</p>
</div>
<div class="paragraph">
<p>UnicodeBlock、UnicodeScript</p>
</div>
<div class="paragraph">
<p>UnicodeBlock 主要是一个静态 map 集合，键是字符串，代表哪一类字符，值是 UnicodeBlock。例如中日韩的字符，
CJK_SYMBOLS_AND_PUNCTUATION</p>
</div>
<div class="paragraph">
<p>UnicodeScript：是一个枚举，Unicode script 分类。</p>
</div>
<div class="paragraph">
<p>（5）重要的字段</p>
</div>
<div class="paragraph">
<p>blockStarts，这是一个 int 数组。每一个数字都是某一类字符的起始数字，上一类字符的结束数字。例如，下标为 0 的数字是 0x0000，下标为 1 的数字是 0x0080，则 0000..007F
代表 Basic Latin，依次类推，每个相邻的下标数字范围代表一类字符。</p>
</div>
<div class="paragraph">
<p>（6）字符缓存</p>
</div>
<div class="paragraph">
<p>CharacterCache，静态内部类，缓存了0到127，共128个字符。</p>
</div>
<div class="paragraph">
<p>（7）2 分查找法</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java" data-lang="java">public static UnicodeBlock of(int codePoint) {
    if (!isValidCodePoint(codePoint)) {
        throw new IllegalArgumentException();
    }

    int top, bottom, current;
    bottom = 0;
    top = blockStarts.length;
    current = top/2;

    // invariant: top &gt; current &gt;= bottom &amp;&amp; codePoint &gt;= unicodeBlockStarts[bottom]
    while (top - bottom &gt; 1) {
        if (codePoint &gt;= blockStarts[current]) {
            bottom = current;
        } else {
            top = current;
        }
        current = (top + bottom) / 2;
    }
    return blocks[current];
}</code></pre>
</div>
</div>
<div class="paragraph">
<p><strong>扩展</strong></p>
</div>
<div class="paragraph">
<p>CharacterData0E、CharacterData00、CharacterData01、CharacterData02、CharacterDataLatin1、CharacterDataPrivateUse、CharacterDataUndefined</p>
</div>
<div class="paragraph">
<p>这些类都是对字符进行定义操作的一些类，实际用处不大，了解即可。</p>
</div>
<div class="paragraph">
<p><strong>一些方法解析</strong></p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java" data-lang="java">    // 最大值，其二进制是 16 个 1.
    public static final char MAX_VALUE = '\uFFFF';

    // 使用移位运算，小于 max_value 的数字，右移 16 为都应该为 0
    public static boolean isBmpCodePoint(int codePoint) {
        return codePoint &gt;&gt;&gt; 16 == 0;
        // Optimized form of:
        //     codePoint &gt;= MIN_VALUE &amp;&amp; codePoint &lt;= MAX_VALUE
        // We consistently use logical shift (&gt;&gt;&gt;) to facilitate
        // additional runtime optimizations.
    }

    // 同理，判读一个数字是否在一个范围内，都进行右移 16 位，然后比较大小
    public static boolean isValidCodePoint(int codePoint) {
        // Optimized form of:
        //     codePoint &gt;= MIN_CODE_POINT &amp;&amp; codePoint &lt;= MAX_CODE_POINT
        int plane = codePoint &gt;&gt;&gt; 16;
        return plane &lt; ((MAX_CODE_POINT + 1) &gt;&gt;&gt; 16);
    }</code></pre>
</div>
</div>
<div class="paragraph">
<p>如何获取字符其 codepoint ?</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java" data-lang="java">char anyChar = '你';
int number = (int) anyChar;
System.out.println(number);</code></pre>
</div>
</div>
<div class="paragraph">
<p>参考： <a href="https://blog.csdn.net/hyongilfmmm/article/details/112037596" class="bare">https://blog.csdn.net/hyongilfmmm/article/details/112037596</a>
<a href="https://blog.csdn.net/cumtwyc/article/details/45080679" class="bare">https://blog.csdn.net/cumtwyc/article/details/45080679</a></p>
</div>
</div>
<div class="sect2">
<h3 id="_double">1.6. Double</h3>
<div class="paragraph">
<p><strong>定义一些静态常量</strong></p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java" data-lang="java">public static final double POSITIVE_INFINITY = 1.0 / 0.0;

public static final double NEGATIVE_INFINITY = -1.0 / 0.0;

public static final double NaN = 0.0d / 0.0;

public static final double MAX_VALUE = 0x1.fffffffffffffP+1023; // 1.7976931348623157e+308

public static final double MIN_NORMAL = 0x1.0p-1022; // 2.2250738585072014E-308

public static final double MIN_VALUE = 0x0.0000000000001P-1022; // 4.9e-324

public static final int MAX_EXPONENT = 1023;

public static final int MIN_EXPONENT = -1022;

public static final int SIZE = 64;

public static final int BYTES = SIZE / Byte.SIZE;</code></pre>
</div>
</div>
<div class="paragraph">
<p><strong>构造器创建Double对象</strong></p>
</div>
<div class="literalblock">
<div class="content">
<pre>public Double(double value) {
    this.value = value;
}

public Double(String s) throws NumberFormatException {
    value = parseDouble(s);
}

public static double parseDouble(String s) throws NumberFormatException {
    return FloatingDecimal.parseDouble(s);
}</pre>
</div>
</div>
<div class="ulist">
<ul>
<li>
<p>valueOf 创建 Double 对象*</p>
</li>
</ul>
</div>
<div class="literalblock">
<div class="content">
<pre>public static Double valueOf(String s) throws NumberFormatException {
    return new Double(parseDouble(s));
}

public static Double valueOf(double d) {
    return new Double(d);
}</pre>
</div>
</div>
<div class="paragraph">
<p><strong>转字符串</strong></p>
</div>
<div class="literalblock">
<div class="content">
<pre>public String toString() {
    return toString(value);
}

public static String toString(double d) {
    return FloatingDecimal.toJavaFormatString(d);
}

public static String toHexString(double d) {
    /*
     * Modeled after the "a" conversion specifier in C99, section
     * 7.19.6.1; however, the output of this method is more
     * tightly specified.
     */
    if (!isFinite(d) )
        // For infinity and NaN, use the decimal output.
        return Double.toString(d);
    else {
        // Initialized to maximum size of output.
        StringBuilder answer = new StringBuilder(24);

        if (Math.copySign(1.0, d) == -1.0)    // value is negative,
            answer.append("-");                  // so append sign info

        answer.append("0x");

        d = Math.abs(d);

        if(d == 0.0) {
            answer.append("0.0p0");
        } else {
            boolean subnormal = (d &lt; DoubleConsts.MIN_NORMAL);

            // Isolate significand bits and OR in a high-order bit
            // so that the string representation has a known
            // length.
            long signifBits = (Double.doubleToLongBits(d)
                               &amp; DoubleConsts.SIGNIF_BIT_MASK) |
                0x1000000000000000L;

            // Subnormal values have a 0 implicit bit; normal
            // values have a 1 implicit bit.
            answer.append(subnormal ? "0." : "1.");

            // Isolate the low-order 13 digits of the hex
            // representation.  If all the digits are zero,
            // replace with a single 0; otherwise, remove all
            // trailing zeros.
            String signif = Long.toHexString(signifBits).substring(3,16);
            answer.append(signif.equals("0000000000000") ? // 13 zeros
                          "0":
                          signif.replaceFirst("0{1,12}$", ""));

            answer.append('p');
            // If the value is subnormal, use the E_min exponent
            // value for double; otherwise, extract and report d's
            // exponent (the representation of a subnormal uses
            // E_min -1).
            answer.append(subnormal ?
                          DoubleConsts.MIN_EXPONENT:
                          Math.getExponent(d));
        }
        return answer.toString();
    }
}</pre>
</div>
</div>
<div class="paragraph">
<p><strong>判断</strong></p>
</div>
<div class="literalblock">
<div class="content">
<pre>public static boolean isNaN(double v) {
    return (v != v);
}

public static boolean isInfinite(double v) {
    return (v == POSITIVE_INFINITY) || (v == NEGATIVE_INFINITY);
}

public static boolean isFinite(double d) {
    return Math.abs(d) &lt;= DoubleConsts.MAX_VALUE;
}</pre>
</div>
</div>
<div class="paragraph">
<p><strong>继承 Number 类，数值之间转换</strong></p>
</div>
<div class="literalblock">
<div class="content">
<pre>public byte byteValue() {
    return (byte)value;
}

public short shortValue() {
    return (short)value;
}

public int intValue() {
    return (int)value;
}

public long longValue() {
    return (long)value;
}

public float floatValue() {
    return (float)value;
}

public double doubleValue() {
    return value;
}</pre>
</div>
</div>
<div class="paragraph">
<p><strong>hashCode/equals/compare</strong></p>
</div>
<div class="literalblock">
<div class="content">
<pre>public int hashCode() {
    return Double.hashCode(value);
}

public static int hashCode(double value) {
    long bits = doubleToLongBits(value);
    return (int)(bits ^ (bits &gt;&gt;&gt; 32));
}</pre>
</div>
</div>
<div class="literalblock">
<div class="content">
<pre>public boolean equals(Object obj) {
    return (obj instanceof Double)
           &amp;&amp; (doubleToLongBits(((Double)obj).value) ==
                  doubleToLongBits(value));
}</pre>
</div>
</div>
<div class="literalblock">
<div class="content">
<pre>public int compareTo(Double anotherDouble) {
    return Double.compare(value, anotherDouble.value);
}

public static int compare(double d1, double d2) {
    if (d1 &lt; d2)
        return -1;           // Neither val is NaN, thisVal is smaller
    if (d1 &gt; d2)
        return 1;            // Neither val is NaN, thisVal is larger

    // Cannot use doubleToRawLongBits because of possibility of NaNs.
    long thisBits    = Double.doubleToLongBits(d1);
    long anotherBits = Double.doubleToLongBits(d2);

    return (thisBits == anotherBits ?  0 : // Values are equal
            (thisBits &lt; anotherBits ? -1 : // (-0.0, 0.0) or (!NaN, NaN)
             1));                          // (0.0, -0.0) or (NaN, !NaN)
}</pre>
</div>
</div>
<div class="paragraph">
<p><strong>运算</strong></p>
</div>
<div class="literalblock">
<div class="content">
<pre>public static double sum(double a, double b) {
    return a + b;
}


public static double max(double a, double b) {
    return Math.max(a, b);
}

public static double min(double a, double b) {
    return Math.min(a, b);
}</pre>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_float">1.7. Float</h3>
<div class="paragraph">
<p><strong>常量定义</strong></p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java" data-lang="java">public static final float POSITIVE_INFINITY = 1.0f / 0.0f;

public static final float NEGATIVE_INFINITY = -1.0f / 0.0f;

public static final float NaN = 0.0f / 0.0f;

public static final float MAX_VALUE = 0x1.fffffeP+127f; // 3.4028235e+38f

public static final float MIN_NORMAL = 0x1.0p-126f; // 1.17549435E-38f

public static final float MIN_VALUE = 0x0.000002P-126f; // 1.4e-45f

public static final int MAX_EXPONENT = 127;

public static final int MIN_EXPONENT = -126;

public static final int SIZE = 32;

public static final int BYTES = SIZE / Byte.SIZE;

@SuppressWarnings("unchecked")
public static final Class&lt;Float&gt; TYPE = (Class&lt;Float&gt;) Class.getPrimitiveClass("float");</code></pre>
</div>
</div>
<div class="paragraph">
<p><strong>构造器创建 Float 对象</strong></p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java" data-lang="java">public Float(float value) {
    this.value = value;
}

public Float(double value) {
    this.value = (float)value;
}

public Float(String s) throws NumberFormatException {
    value = parseFloat(s);
}

public static float parseFloat(String s) throws NumberFormatException {
    return FloatingDecimal.parseFloat(s);
}</code></pre>
</div>
</div>
<div class="paragraph">
<p><strong>valueOf 创建 Float 对象</strong></p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java" data-lang="java">public static Float valueOf(String s) throws NumberFormatException {
    return new Float(parseFloat(s));
}
public static Float valueOf(float f) {
    return new Float(f);
}</code></pre>
</div>
</div>
<div class="paragraph">
<p><strong>转字符串</strong></p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java" data-lang="java">public String toString() {
    return Float.toString(value);
}
public static String toString(float f) {
    return FloatingDecimal.toJavaFormatString(f);
}
public static String toHexString(float f) {
    if (Math.abs(f) &lt; FloatConsts.MIN_NORMAL
        &amp;&amp;  f != 0.0f ) {// float subnormal
        // Adjust exponent to create subnormal double, then
        // replace subnormal double exponent with subnormal float
        // exponent
        String s = Double.toHexString(Math.scalb((double)f,
                                                 /* -1022+126 */
                                                 DoubleConsts.MIN_EXPONENT-
                                                 FloatConsts.MIN_EXPONENT));
        return s.replaceFirst("p-1022$", "p-126");
    }
    else // double string will be the same as float string
        return Double.toHexString(f);
}</code></pre>
</div>
</div>
<div class="paragraph">
<p><strong>Float对象判断</strong></p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java" data-lang="java">public static boolean isNaN(float v) {
    return (v != v);
}


public static boolean isInfinite(float v) {
    return (v == POSITIVE_INFINITY) || (v == NEGATIVE_INFINITY);
}

 public static boolean isFinite(float f) {
    return Math.abs(f) &lt;= FloatConsts.MAX_VALUE;
}

public boolean isNaN() {
    return isNaN(value);
}


public boolean isInfinite() {
    return isInfinite(value);
}</code></pre>
</div>
</div>
<div class="paragraph">
<p><strong>继承Nubmer类，实现数值转换方法</strong></p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java" data-lang="java">public byte byteValue() {
    return (byte)value;
}

public short shortValue() {
    return (short)value;
}

public int intValue() {
    return (int)value;
}

public long longValue() {
    return (long)value;
}

public float floatValue() {
    return value;
}

public double doubleValue() {
    return (double)value;
}</code></pre>
</div>
</div>
<div class="paragraph">
<p><strong>hashCode/equals/compare</strong></p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java" data-lang="java">@Override
public int hashCode() {
    return Float.hashCode(value);
}

public static int hashCode(float value) {
    return floatToIntBits(value);
}</code></pre>
</div>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java" data-lang="java">public boolean equals(Object obj) {
    return (obj instanceof Float)
           &amp;&amp; (floatToIntBits(((Float)obj).value) == floatToIntBits(value));
}</code></pre>
</div>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java" data-lang="java">public int compareTo(Float anotherFloat) {
    return Float.compare(value, anotherFloat.value);
}
public static int compare(float f1, float f2) {
    if (f1 &lt; f2)
        return -1;           // Neither val is NaN, thisVal is smaller
    if (f1 &gt; f2)
        return 1;            // Neither val is NaN, thisVal is larger

    // Cannot use floatToRawIntBits because of possibility of NaNs.
    int thisBits    = Float.floatToIntBits(f1);
    int anotherBits = Float.floatToIntBits(f2);

    return (thisBits == anotherBits ?  0 : // Values are equal
            (thisBits &lt; anotherBits ? -1 : // (-0.0, 0.0) or (!NaN, NaN)
             1));                          // (0.0, -0.0) or (NaN, !NaN)
}</code></pre>
</div>
</div>
<div class="paragraph">
<p><strong>运算</strong></p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java" data-lang="java">public static float sum(float a, float b) {
    return a + b;
}

public static float max(float a, float b) {
    return Math.max(a, b);
}

public static float min(float a, float b) {
    return Math.min(a, b);
}</code></pre>
</div>
</div>
<div class="paragraph">
<p><strong>其他方法</strong></p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java" data-lang="java">public static int floatToIntBits(float value) {
    int result = floatToRawIntBits(value);
    // Check for NaN based on values of bit fields, maximum
    // exponent and nonzero significand.
    if ( ((result &amp; FloatConsts.EXP_BIT_MASK) ==
          FloatConsts.EXP_BIT_MASK) &amp;&amp;
         (result &amp; FloatConsts.SIGNIF_BIT_MASK) != 0)
        result = 0x7fc00000;
    return result;
}
public static native int floatToRawIntBits(float value);

public static native float intBitsToFloat(int bits);</code></pre>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_integer">1.8. Integer</h3>
<div class="paragraph">
<p><strong>对象缓存</strong></p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java" data-lang="java">private static class IntegerCache {
    static final int low = -128;
    static final int high;
    static final Integer cache[];

    static {
        // high value may be configured by property
        int h = 127;
        String integerCacheHighPropValue =
            sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
        if (integerCacheHighPropValue != null) {
            try {
                int i = parseInt(integerCacheHighPropValue);
                i = Math.max(i, 127);
                // Maximum array size is Integer.MAX_VALUE
                h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
            } catch( NumberFormatException nfe) {
                // If the property cannot be parsed into an int, ignore it.
            }
        }
        high = h;

        cache = new Integer[(high - low) + 1];
        int j = low;
        for(int k = 0; k &lt; cache.length; k++)
            cache[k] = new Integer(j++);

        // range [-128, 127] must be interned (JLS7 5.1.7)
        assert IntegerCache.high &gt;= 127;
    }

    private IntegerCache() {}
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>从上面代码可以看出</p>
</div>
<div class="olist arabic">
<ol class="arabic">
<li>
<p>指定返回类的数值必须缓存，</p>
</li>
<li>
<p>缓存最小值是 -128，最大值可以通过程序设置，如果不设置就是默认值 127</p>
</li>
<li>
<p>可以通过设置 <code>java.lang.Integer.IntegerCache.high</code>
设置缓存的最大值。</p>
</li>
<li>
<p>缓存值存放在一个静态数组中。</p>
</li>
<li>
<p>如果定义的值在缓存中，无论怎么赋值，都是同一个 Integer 对象。</p>
</li>
</ol>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java" data-lang="java">Integer a = 1;
Integer b = Integer.valueOf(1);
// a == b  true;</code></pre>
</div>
</div>
<div class="paragraph">
<p><strong>构造 Integer 对象</strong></p>
</div>
<div class="paragraph">
<p>方式一：通过构造器</p>
</div>
<div class="literalblock">
<div class="content">
<pre>public Integer(int value) {
    this.value = value;
}

public Integer(String s) throws NumberFormatException {
    this.value = parseInt(s, 10);
}</pre>
</div>
</div>
<div class="paragraph">
<p>方式二：通过静态方法，最终都是通过构造器创建 Integer 对象</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java" data-lang="java">public static Integer valueOf(String s, int radix) throws NumberFormatException {
    return Integer.valueOf(parseInt(s,radix));
}

public static Integer valueOf(String s) throws NumberFormatException {
    return Integer.valueOf(parseInt(s, 10));
}

// 注意：如果值在缓存范围内，则从缓存数组中取值。
public static Integer valueOf(int i) {
    if (i &gt;= IntegerCache.low &amp;&amp; i &lt;= IntegerCache.high)
        return IntegerCache.cache[i + (-IntegerCache.low)];
    return new Integer(i);
}</code></pre>
</div>
</div>
<div class="paragraph">
<p><strong>转字符串</strong></p>
</div>
<div class="paragraph">
<p>（1）toString(int, int): String</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java" data-lang="java">public static String toString(int i, int radix) {
    if (radix &lt; Character.MIN_RADIX || radix &gt; Character.MAX_RADIX)
        radix = 10;

    if (radix == 10) {
        return toString(i);
    }

    char buf[] = new char[33];
    boolean negative = (i &lt; 0);
    int charPos = 32;

    if (!negative) {
        i = -i;
    }

    // int型的最大值为2147483647，最小值为 -2147483648；
    // 如果将负数转为正数，最小值在转时会溢出，故使用负数来进行运行
    while (i &lt;= -radix) {
        buf[charPos--] = digits[-(i % radix)];
        i = i / radix;
    }
    buf[charPos] = digits[-i];

    if (negative) {
        buf[--charPos] = '-';
    }

    return new String(buf, charPos, (33 - charPos));
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>好的代码，本身就是说明解释，其他说明反而显得画蛇添足</p>
</div>
<div class="olist arabic">
<ol class="arabic">
<li>
<p>如果进制不在规定范围内，默认采用 10 进制</p>
</li>
<li>
<p>如果是十进制，直接使用另一个 toString 方法</p>
</li>
<li>
<p>定义了一个容量为 33 的 char 数组，int 值存放，4 个字节，32 位，加一个正负号字符，共 33。</p>
</li>
<li>
<p>先判断数值正负，如果正数，先转为负数，根据进制进行运算，并把每次运算的结果放入定义好的 char 数组中（顺序是从后往前）。这里是主要的算法逻辑。</p>
</li>
<li>
<p>最后通过构建 String 对象，实现 Integer 转 String。</p>
</li>
</ol>
</div>
<div class="paragraph">
<p>这里涉及到一个10进制转其他进制的一个方法。</p>
</div>
<div class="paragraph">
<p>如10进制转2进制，其他进制，把除数2改为对应进制就行：</p>
</div>
<div class="paragraph">
<p>789 = 1100010101(B) 789/2=394 余1 第10位 394/2=197 余0 第9位 197/2=98
余1 第8位 98/2=49 余0 第7位 49/2=24 余1 第6位 24/2=12 余0 第5位 12/2=6
余0 第4位 6/2=3 余0 第3位 3/2=1 余1 第2位 1/2=0 余1 第1位</p>
</div>
<div class="paragraph">
<p>转换为下面代码：</p>
</div>
<div class="literalblock">
<div class="content">
<pre>while (i &lt;= -radix) {
    // 根据radix取余，再从digits数组中取出radix下对应的字符，放入buf数组中，从尾部往前放
    buf[charPos--] = digits[-(i % radix)];
    // 一次取余后，进行除法运算得到下一个数，再循环取余。
    i = i / radix;
}
// 最后一位，也即i的值，既是第一位
buf[charPos] = digits[-i];</pre>
</div>
</div>
<div class="paragraph">
<p>（2）toUnsignedString(int, int): String</p>
</div>
<div class="paragraph">
<p>调用Long类函数，这里不做分析</p>
</div>
<div class="paragraph">
<p>（3）转进制格式方法</p>
</div>
<div class="paragraph">
<p>16进制：toHexString(int): String</p>
</div>
<div class="paragraph">
<p>8进制：toOctalString(int): String</p>
</div>
<div class="paragraph">
<p>2进制：toBinaryString(int): String</p>
</div>
<div class="paragraph">
<p>这个转换底层都是调用，toUnsignedString0(int val, int shift)方法</p>
</div>
<div class="literalblock">
<div class="content">
<pre>private static String toUnsignedString0(int val, int shift) {
    // 计算出2进制数的位数
    int mag = Integer.SIZE - Integer.numberOfLeadingZeros(val);
    int chars = Math.max(((mag + (shift - 1)) / shift), 1);
    char[] buf = new char[chars];

    formatUnsignedInt(val, shift, buf, 0, chars);

    // Use special constructor which takes over "buf".
    return new String(buf, true);
}</pre>
</div>
</div>
<div class="literalblock">
<div class="content">
<pre>/**
* 计算出一个2进制数，前面的0的个数
*/
public static int numberOfLeadingZeros(int i) {
    // HD, Figure 5-6
    if (i == 0)
        return 32;
    int n = 1;
    if (i &gt;&gt;&gt; 16 == 0) { n += 16; i &lt;&lt;= 16; }
    if (i &gt;&gt;&gt; 24 == 0) { n +=  8; i &lt;&lt;=  8; }
    if (i &gt;&gt;&gt; 28 == 0) { n +=  4; i &lt;&lt;=  4; }
    if (i &gt;&gt;&gt; 30 == 0) { n +=  2; i &lt;&lt;=  2; }
    n -= i &gt;&gt;&gt; 31;
    return n;
}</pre>
</div>
</div>
<div class="literalblock">
<div class="content">
<pre> static int formatUnsignedInt(int val, int shift, char[] buf, int offset, int len) {
    int charPos = len;
    int radix = 1 &lt;&lt; shift;
    // 掩码，作用是与val进行&amp;运算，保留最后
    int mask = radix - 1;
    do {
        buf[offset + --charPos] = Integer.digits[val &amp; mask];
        val &gt;&gt;&gt;= shift;
    } while (val != 0 &amp;&amp; charPos &gt; 0);

    return charPos;
}</pre>
</div>
</div>
<div class="paragraph">
<p>具体参考https://blog.csdn.net/lianjiww/article/details/90183672</p>
</div>
<div class="paragraph">
<p>（4）toString(int): String 方法详解</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java" data-lang="java">public static String toString(int i) {
    if (i == Integer.MIN_VALUE)
        return "-2147483648";
    int size = (i &lt; 0) ? stringSize(-i) + 1 : stringSize(i);
    char[] buf = new char[size];
    getChars(i, size, buf);
    return new String(buf, true);
}</code></pre>
</div>
</div>
<div class="olist arabic">
<ol class="arabic">
<li>
<p>如果是最小值，直接返回最小值的字符串格式</p>
</li>
<li>
<p>接着求 size，如果是负数，转正数，长度加一。关键 stringSize 函数</p>
</li>
<li>
<p>然后 getChars 将 i 转为对应的字符数组</p>
</li>
<li>
<p>使用 String 的构造器创建字符串。</p>
</li>
</ol>
</div>
<div class="paragraph">
<p>stringSize 详解</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java" data-lang="java">final static int [] sizeTable = { 9, 99, 999, 9999, 99999, 999999, 9999999,
                                  99999999, 999999999, Integer.MAX_VALUE };

// 依次和sizeTable的数字比较，如果数小于比较数，则该位置的下标加1，既是长度。
static int stringSize(int x) {
    for (int i=0; ; i++)
        if (x &lt;= sizeTable[i])
            return i+1;
}</code></pre>
</div>
</div>
<div class="paragraph">
<p><strong>getChar解析</strong></p>
</div>
<div class="literalblock">
<div class="content">
<pre>/**
* 思路：定义了一个char 数组，每次取数字最后一位，放入char数组最后一位。直到最顶位。
* 例如 数字23423435
* 如果数字大于65536， 每次想法获取后两位，35，剩下234234，满足条件，* 再次循环。
* 当数字小于65536，每次想法获取个位数，例如 2342 ，每次获取个位数。
*
*/
static void getChars(int i, int index, char[] buf) {
    // 例如 678380 除以 100 来得到2个结果， q=6783 r=80
    int q, r;
    // 直接将index命名为charPos不行吗？为什么需要重新定义一个变量？多此一举
    int charPos = index;
    char sign = 0;
    // 判断是否为负数。
    if (i &lt; 0) {
        sign = '-';
        i = -i;
    }

    // 如果数大于65536，则每次操作除以100，得到拆分后的2个部分。
    // 例如 678380 除以 100 来得到2个结果， q=6783 r=80
    // 每次循环，作用是取数字的后两位，来得到结果。
    while (i &gt;= 65536) {
        q = i / 100;
        // 等价于 r = i - q*100, 也即获取数字的后两位。
        r = i - ((q &lt;&lt; 6) + (q &lt;&lt; 5) + (q &lt;&lt; 2));
        // 将去掉后两位的数字，在复制给i，再次进行循环。
        i = q;

        // 这里是获取到的数字后两位，结合DigitOnes和DigitTens找出十位数字以及个位数字的字符串形式。这里以获取的80为例
        // 个位：第八排第一个数，就是0
        buf [--charPos] = DigitOnes[r];
        // 十位：第八排，无论个位数是几，十位始终是8,
        buf [--charPos] = DigitTens[r];
    }

    // 数字小于65536，则采用除10来通过获取个位数来获取对应的字符
    for (;;) {
        // 含义是除10
        q = (i * 52429) &gt;&gt;&gt; (16+3);

        // 这里相当于 r = i-(q*10) ，r直接是个位数字
        r = i - ((q &lt;&lt; 3) + (q &lt;&lt; 1));
        // 个位数字直接查找数值对应的字符，直到最后一位。
        buf [--charPos] = digits [r];
        i = q;
        if (i == 0) break;
    }
    if (sign != 0) {
        buf [--charPos] = sign;
    }
}</pre>
</div>
</div>
<div class="literalblock">
<div class="content">
<pre>final static char [] DigitTens = {
    '0', '0', '0', '0', '0', '0', '0', '0', '0', '0',
    '1', '1', '1', '1', '1', '1', '1', '1', '1', '1',
    '2', '2', '2', '2', '2', '2', '2', '2', '2', '2',
    '3', '3', '3', '3', '3', '3', '3', '3', '3', '3',
    '4', '4', '4', '4', '4', '4', '4', '4', '4', '4',
    '5', '5', '5', '5', '5', '5', '5', '5', '5', '5',
    '6', '6', '6', '6', '6', '6', '6', '6', '6', '6',
    '7', '7', '7', '7', '7', '7', '7', '7', '7', '7',
    '8', '8', '8', '8', '8', '8', '8', '8', '8', '8',
    '9', '9', '9', '9', '9', '9', '9', '9', '9', '9',
    } ;

final static char [] DigitOnes = {
    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
    } ;</pre>
</div>
</div>
<div class="olist arabic">
<ol class="arabic" start="5">
<li>
<p>字符串转 int</p>
</li>
</ol>
</div>
<div class="literalblock">
<div class="content">
<pre>1 parseInt(String s, int radix)

2 parseInt(String s)

3 parseUnsignedInt(String s, int radix)

4 parseUnsignedInt(String s)</pre>
</div>
</div>
<div class="paragraph">
<p>2 和 4，主要是默认进制是 10，分别调用的 1 和 3</p>
</div>
<div class="paragraph">
<p>解析 parseInt(String s, int radix)</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java" data-lang="java">public static int parseInt(String s, int radix)
            throws NumberFormatException
{
    /*
     * WARNING: This method may be invoked early during VM initialization
     * before IntegerCache is initialized. Care must be taken to not use
     * the valueOf method.
     */
    if (s == null) {
        throw new NumberFormatException("null");
    }

    if (radix &lt; Character.MIN_RADIX) {
        throw new NumberFormatException("radix " + radix +
                                        " less than Character.MIN_RADIX");
    }

    if (radix &gt; Character.MAX_RADIX) {
        throw new NumberFormatException("radix " + radix +
                                        " greater than Character.MAX_RADIX");
    }

    int result = 0;
    boolean negative = false;
    // i的作用，是依次递增查找字符串上的数字
    int i = 0, len = s.length();
    int limit = -Integer.MAX_VALUE;
    int multmin;
    // 字符串数字对应的值。
    int digit;

    if (len &gt; 0) {
        char firstChar = s.charAt(0);

        // 这里判断第一位是否是符号
        if (firstChar &lt; '0') { // Possible leading "+" or "-"
            if (firstChar == '-') {
                negative = true;
                limit = Integer.MIN_VALUE;
            } else if (firstChar != '+')
                throw NumberFormatException.forInputString(s);

            // 不能只是一个 "+" or "-"
            if (len == 1)
                throw NumberFormatException.forInputString(s);
            i++;
        }
        multmin = limit / radix;
        // 思路是，从字符串的第一位开始取值，每次乘以进制，在加上当前位置的数字。
        // 例如 "12535"， 10进制 , 第一次，初始值是result=0, 0*进制10，减去第一位1，得到result为-1，第二次，初始值是result=-1,-1*进制10，减去第二位数字2，得到-12，后面，同理。其中有一些异常判断。
        while (i &lt; len) {
            // Accumulating negatively avoids surprises near MAX_VALUE
            digit = Character.digit(s.charAt(i++),radix);
            if (digit &lt; 0) {
                throw NumberFormatException.forInputString(s);
            }
            if (result &lt; multmin) {
                throw NumberFormatException.forInputString(s);
            }
            result *= radix;
            if (result &lt; limit + digit) {
                throw NumberFormatException.forInputString(s);
            }
            result -= digit;
        }
    } else {
        throw NumberFormatException.forInputString(s);
    }
    return negative ? result : -result;
}</code></pre>
</div>
</div>
<div class="olist arabic">
<ol class="arabic" start="6">
<li>
<p>String 转无符号 int</p>
</li>
</ol>
</div>
<div class="literalblock">
<div class="content">
<pre>public static int parseUnsignedInt(String s, int radix)
public static int parseUnsignedInt(String s)</pre>
</div>
</div>
<div class="literalblock">
<div class="content">
<pre>public static int parseUnsignedInt(String s, int radix)
            throws NumberFormatException {
    if (s == null)  {
        throw new NumberFormatException("null");
    }

    int len = s.length();
    if (len &gt; 0) {
        char firstChar = s.charAt(0);
        if (firstChar == '-') {
            throw new
                NumberFormatException(String.format("Illegal leading minus sign " +
                                                   "on unsigned string %s.", s));
        } else {
            // int 最大值采用最大进制表示，有5位数字，用10进制表示有10位数字
            if (len &lt;= 5 ||
                (radix == 10 &amp;&amp; len &lt;= 9) ) {
                return parseInt(s, radix);
            } else {
                long ell = Long.parseLong(s, radix);
                if ((ell &amp; 0xffff_ffff_0000_0000L) == 0) {
                    return (int) ell;
                } else {
                    throw new
                        NumberFormatException(String.format("String value %s exceeds " +
                                                            "range of unsigned int.", s));
                }
            }
        }
    } else {
        throw NumberFormatException.forInputString(s);
    }
}</pre>
</div>
</div>
<div class="paragraph">
<p>疑问：为什么要采用Long的转换方法，本身的parseInt，解析超出范围的数字也会抛异常吧？</p>
</div>
<div class="olist arabic">
<ol class="arabic" start="7">
<li>
<p>创建 Integer 对象：</p>
</li>
</ol>
</div>
<div class="literalblock">
<div class="content">
<pre>public static Integer valueOf(String s, int radix)
public static Integer valueOf(String s)
public static Integer valueOf(int i)</pre>
</div>
</div>
<div class="paragraph">
<p>String 类型参数，会调用 parseInt 方法转为 int，再创建 Integer 对象，如果数字在缓存内，则从缓存取。</p>
</div>
<div class="paragraph">
<p>（8）继承 Number 类，需要实现各个类型之间的数值转换。</p>
</div>
<div class="literalblock">
<div class="content">
<pre>public byte byteValue() {
    return (byte)value;
}

public short shortValue() {
    return (short)value;
}

public int intValue() {
    return value;
}

public long longValue() {
    return (long)value;
}

public float floatValue() {
    return (float)value;
}

public double doubleValue() {
    return (double)value;
}</pre>
</div>
</div>
<div class="paragraph">
<p>（9）hashCode、equals</p>
</div>
<div class="literalblock">
<div class="content">
<pre>@Override
public int hashCode() {
    return Integer.hashCode(value);
}

public static int hashCode(int value) {
    return value;
}

// 实际比较的是数值。
public boolean equals(Object obj) {
    if (obj instanceof Integer) {
        return value == ((Integer)obj).intValue();
    }
        return false;
}</pre>
</div>
</div>
<div class="paragraph">
<p>（10）getInteger 系列方法</p>
</div>
<div class="literalblock">
<div class="content">
<pre>public static Integer getInteger(String nm) {
    return getInteger(nm, null);
}
public static Integer getInteger(String nm, int val) {
    Integer result = getInteger(nm, null);
    return (result == null) ? Integer.valueOf(val) :    result;
}
//
public static Integer getInteger(String nm, Integer val) {
    String v = null;
    try {
        // 若返回的系统value不是可decode的字符串，就抛出NumberFormatException
       // 例如：System.getProperty("sun.arch.data.model")
       // 而System.getProperty("java.version")，则报错
       // System.getProperties().list(System.out);这个语句可以打印所有系统属性可取的key
        v = System.getProperty(nm);
    } catch (IllegalArgumentException | NullPointerException e) {
    }
    if (v != null) {
        try {
            return Integer.decode(v);
        } catch (NumberFormatException e) {
        }
    }
    return val;
}</pre>
</div>
</div>
<div class="olist arabic">
<ol class="arabic" start="11">
<li>
<p>decode 方法</p>
</li>
</ol>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java" data-lang="java">public static Integer decode(String nm) throws NumberFormatException {
    int radix = 10;
    int index = 0;
    boolean negative = false;
    Integer result;

    if (nm.length() == 0)
        throw new NumberFormatException("Zero length string");
    char firstChar = nm.charAt(0);
    // 判断符号
    if (firstChar == '-') {
        negative = true;
        index++;
    } else if (firstChar == '+')
        index++;

    // 判断进制
    if (nm.startsWith("0x", index) || nm.startsWith("0X", index)) {
        index += 2;
        radix = 16;
    }
    else if (nm.startsWith("#", index)) {
        index ++;
        radix = 16;
    }
    else if (nm.startsWith("0", index) &amp;&amp; nm.length() &gt; 1 + index) {
        index ++;
        radix = 8;
    }

    if (nm.startsWith("-", index) || nm.startsWith("+", index))
        throw new NumberFormatException("Sign character in wrong position");

    try {
        result = Integer.valueOf(nm.substring(index), radix);
        result = negative ? Integer.valueOf(-result.intValue()) : result;
    } catch (NumberFormatException e) {
        // int 最小值在这里处理。
        String constant = negative ? ("-" + nm.substring(index))
                                   : nm.substring(index);
        result = Integer.valueOf(constant, radix);
    }
    return result;
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>从字符串中推测出正负号、进制，并截取实际数字位，使用 valueOf</p>
</div>
<div class="paragraph">
<p>转为 int 数字，最终添加符号位，并返回。</p>
</div>
<div class="paragraph">
<p>（12）compare 系列方法</p>
</div>
<div class="literalblock">
<div class="content">
<pre>public int compareTo(Integer anotherInteger) {
    return compare(this.value, anotherInteger.value);
}
public static int compare(int x, int y){
    return (x &lt; y) ? -1 : ((x == y) ? 0 : 1);
}
// 1.8新增
public static int compareUnsigned(int x, int y) {
    return compare(x + MIN_VALUE, y + MIN_VALUE);
}</pre>
</div>
</div>
<div class="paragraph">
<p>（13）1.8 新增运算</p>
</div>
<div class="literalblock">
<div class="content">
<pre>public static long toUnsignedLong(int x) {
    return ((long) x) &amp; 0xffffffffL;
}

// 除
public static int divideUnsigned(int dividend, int divisor) {
// In lieu of tricky code, for now just use long arithmetic.
    return (int)(toUnsignedLong(dividend) /     toUnsignedLong(divisor));
}

// 求余
public static int remainderUnsigned(int dividend, int divisor) {
// In lieu of tricky code, for now just use long arithmetic.
    return (int)(toUnsignedLong(dividend) % toUnsignedLong(divisor));
}</pre>
</div>
</div>
<div class="paragraph">
<p>（14）highestOneBit、lowestOneBit</p>
</div>
<div class="paragraph">
<p><a href="https://blog.csdn.net/zhangsai3593/article/details/78963295" class="bare">https://blog.csdn.net/zhangsai3593/article/details/78963295</a></p>
</div>
<div class="paragraph">
<p><a href="https://blog.csdn.net/Jiapengcs/article/details/73321638" class="bare">https://blog.csdn.net/Jiapengcs/article/details/73321638</a></p>
</div>
<div class="literalblock">
<div class="content">
<pre>public static int highestOneBit(int i) {
    // HD, Figure 3-1
    i |= (i &gt;&gt;  1);
    i |= (i &gt;&gt;  2);
    i |= (i &gt;&gt;  4);
    i |= (i &gt;&gt;  8);
    i |= (i &gt;&gt; 16);
    return i - (i &gt;&gt;&gt; 1);
}</pre>
</div>
</div>
<div class="literalblock">
<div class="content">
<pre>public static int lowestOneBit(int i) {
    // HD, Section 2-1
    return i &amp; -i;
}</pre>
</div>
</div>
<div class="paragraph">
<p>（15）numberOfLeadingZeros、numberOfTrailingZeros</p>
</div>
<div class="literalblock">
<div class="content">
<pre>// 参考：https://www.jianshu.com/p/2c1be41f6e59
public static int numberOfLeadingZeros(int i) {
    // HD, Figure 5-6
    if (i == 0)
        return 32;
    int n = 1;
    if (i &gt;&gt;&gt; 16 == 0) { n += 16; i &lt;&lt;= 16; }
    if (i &gt;&gt;&gt; 24 == 0) { n +=  8; i &lt;&lt;=  8; }
    if (i &gt;&gt;&gt; 28 == 0) { n +=  4; i &lt;&lt;=  4; }
    if (i &gt;&gt;&gt; 30 == 0) { n +=  2; i &lt;&lt;=  2; }
    n -= i &gt;&gt;&gt; 31;
    return n;
}
// https://blog.csdn.net/tina_tian1/article/details/78364795
public static int numberOfTrailingZeros(int i) {
    // HD, Figure 5-14
    int y;
    if (i == 0) return 32;
    int n = 31;
    y = i &lt;&lt;16; if (y != 0) { n = n -16; i = y; }
    y = i &lt;&lt; 8; if (y != 0) { n = n - 8; i = y; }
    y = i &lt;&lt; 4; if (y != 0) { n = n - 4; i = y; }
    y = i &lt;&lt; 2; if (y != 0) { n = n - 2; i = y; }
    return n - ((i &lt;&lt; 1) &gt;&gt;&gt; 31);
}

// https://blog.csdn.net/cor_twi/article/details/53720640
public static int bitCount(int i) {
    // HD, Figure 5-2
    i = i - ((i &gt;&gt;&gt; 1) &amp; 0x55555555);
    i = (i &amp; 0x33333333) + ((i &gt;&gt;&gt; 2) &amp; 0x33333333);
    i = (i + (i &gt;&gt;&gt; 4)) &amp; 0x0f0f0f0f;
    i = i + (i &gt;&gt;&gt; 8);
    i = i + (i &gt;&gt;&gt; 16);
    return i &amp; 0x3f;
}

// https://blog.csdn.net/zuoyouzouzou/article/details/88892198
public static int rotateLeft(int i, int distance) {
    return (i &lt;&lt; distance) | (i &gt;&gt;&gt; -distance);
}

// https://blog.csdn.net/zuoyouzouzou/article/details/88892198
public static int rotateRight(int i, int distance) {
    return (i &gt;&gt;&gt; distance) | (i &lt;&lt; -distance);
}

//
public static int reverse(int i) {
// HD, Figure 7-1
i = (i &amp; 0x55555555) &lt;&lt; 1 | (i &gt;&gt;&gt; 1) &amp; 0x55555555;
i = (i &amp; 0x33333333) &lt;&lt; 2 | (i &gt;&gt;&gt; 2) &amp; 0x33333333;
i = (i &amp; 0x0f0f0f0f) &lt;&lt; 4 | (i &gt;&gt;&gt; 4) &amp; 0x0f0f0f0f;
i = (i &lt;&lt; 24) | ((i &amp; 0xff00) &lt;&lt; 8) |
((i &gt;&gt;&gt; 8) &amp; 0xff00) | (i &gt;&gt;&gt; 24);
return i;
}

// https://www.nhooo.com/note/qa0zb9.html
public static int signum(int i) {
    // HD, Section 2-7
    return (i &gt;&gt; 31) | (-i &gt;&gt;&gt; 31);
}


public static int reverseBytes(int i) {
    return ((i &gt;&gt;&gt; 24)           ) |
    ((i &gt;&gt;   8) &amp;   0xFF00) |
    ((i &lt;&lt;   8) &amp; 0xFF0000) |
    ((i &lt;&lt; 24));
}</pre>
</div>
</div>
<div class="paragraph">
<p>（15）运算</p>
</div>
<div class="literalblock">
<div class="content">
<pre>public static int sum(int a, int b) {
    return a + b;
}
public static int max(int a, int b) {
    return Math.max(a, b);
}
public static int min(int a, int b) {
    return Math.min(a, b);
}</pre>
</div>
</div>
<div class="paragraph">
<p><strong>注意点：</strong></p>
</div>
<div class="olist arabic">
<ol class="arabic">
<li>
<p>缓存问题</p>
</li>
</ol>
</div>
<div class="paragraph">
<p>通过构造器创建的 Integer 对象，使用==，不会取缓存中的值，只有通过静态方法获取的 Integer 对象，在缓存范围内适用 ==。</p>
</div>
<div class="literalblock">
<div class="content">
<pre>Integer q1 = new Integer(111);
Integer q2 = new Integer(111);
System.out.println(q1 == q2);// false</pre>
</div>
</div>
<div class="olist arabic">
<ol class="arabic" start="2">
<li>
<p>核心功能，创建 Integer 对象，转字符串对象，运算，不常用的一些操作方法。</p>
</li>
</ol>
</div>
</div>
<div class="sect2">
<h3 id="_long">1.9. Long</h3>
<div class="paragraph">
<p><strong>缓存</strong></p>
</div>
<div class="literalblock">
<div class="content">
<pre>private static class LongCache {
    private LongCache(){}

    static final Long cache[] = new Long[-(-128) + 127 + 1];

    static {
        for(int i = 0; i &lt; cache.length; i++)
            cache[i] = new Long(i - 128);
    }
}</pre>
</div>
</div>
<div class="olist arabic">
<ol class="arabic">
<li>
<p>不同于Integer，缓存返回不可自由设置，固定-128 ~ 127</p>
</li>
<li>
<p>通过构造器创建的Long对象，不会从缓存中取值，==不适用</p>
</li>
</ol>
</div>
<div class="paragraph">
<p><strong>转化成不同进制下的字符串。</strong></p>
</div>
<div class="literalblock">
<div class="content">
<pre>public static String toString(long i, int radix) {
    if (radix &lt; Character.MIN_RADIX || radix &gt; Character.MAX_RADIX)
        radix = 10;
    if (radix == 10)
        return toString(i);
    char[] buf = new char[65];
    int charPos = 64;
    boolean negative = (i &lt; 0);

    if (!negative) {
        i = -i;
    }

    while (i &lt;= -radix) {
        buf[charPos--] = Integer.digits[(int)(-(i % radix))];
        i = i / radix;
    }
    buf[charPos] = Integer.digits[(int)(-i)];

    if (negative) {
        buf[--charPos] = '-';
    }

    return new String(buf, charPos, (65 - charPos));
}</pre>
</div>
</div>
<div class="paragraph">
<p>同理Integer，不同在于位数不同。</p>
</div>
<div class="literalblock">
<div class="content">
<pre>public static String toUnsignedString(long i) {
    return toUnsignedString(i, 10);
}

public static String toUnsignedString(long i, int radix) {
    if (i &gt;= 0)
        return toString(i, radix);// 正数直接使用toString转换
    else {
        // 负数需要根据进制使用不同的转换方式
        switch (radix) {
        case 2:
            return toBinaryString(i);

        case 4:
            return toUnsignedString0(i, 2);

        case 8:
            return toOctalString(i);

        case 10:

            long quot = (i &gt;&gt;&gt; 1) / 5;
            long rem = i - quot * 10;
            return toString(quot) + rem;

        case 16:
            return toHexString(i);

        case 32:
            return toUnsignedString0(i, 5);

        default:
            return toUnsignedBigInteger(i).toString(radix);
        }
    }
}</pre>
</div>
</div>
<div class="literalblock">
<div class="content">
<pre>/**
* 如果是正数，采用BigInteger.valueOf创建BigInteger对象
* 如果是负数，则拆分为高位和地位两个数，分别转换为无符号Long，再转为BigInteger,最后相加。
*/
private static BigInteger toUnsignedBigInteger(long i) {
    if (i &gt;= 0L)
        return BigInteger.valueOf(i);
    else {
        int upper = (int) (i &gt;&gt;&gt; 32);
        int lower = (int) i;

        // return (upper &lt;&lt; 32) + lower
        return (BigInteger.valueOf(Integer.toUnsignedLong(upper))).shiftLeft(32).
            add(BigInteger.valueOf(Integer.toUnsignedLong(lower)));
    }
}</pre>
</div>
</div>
<div class="literalblock">
<div class="content">
<pre>public static String toHexString(long i) {
    return toUnsignedString0(i, 4);
}
public static String toOctalString(long i) {
    return toUnsignedString0(i, 3);
}
public static String toBinaryString(long i) {
    return toUnsignedString0(i, 1);
}


static String toUnsignedString0(long val, int shift) {
    // 确定val的位数
    int mag = Long.SIZE - Long.numberOfLeadingZeros(val);
    int chars = Math.max(((mag + (shift - 1)) / shift), 1);
    char[] buf = new char[chars];

    formatUnsignedLong(val, shift, buf, 0, chars);
    return new String(buf, true);
}

/**
* 求一个数二进制表示，前面为0的个数。负数符号位为1，前面0个数为0
* 这里和Integer的类似，只不过，多以一步操作， i&gt;&gt;&gt;32, 将一个数变小了。
*/
public static int numberOfLeadingZeros(long i) {
    // HD, Figure 5-6
    if (i == 0)
        return 64;
    int n = 1;
    int x = (int)(i &gt;&gt;&gt; 32);
    if (x == 0) { n += 32; x = (int)i; }
    if (x &gt;&gt;&gt; 16 == 0) { n += 16; x &lt;&lt;= 16; }
    if (x &gt;&gt;&gt; 24 == 0) { n +=  8; x &lt;&lt;=  8; }
    if (x &gt;&gt;&gt; 28 == 0) { n +=  4; x &lt;&lt;=  4; }
    if (x &gt;&gt;&gt; 30 == 0) { n +=  2; x &lt;&lt;=  2; }
    n -= x &gt;&gt;&gt; 31;
    return n;
}


static int formatUnsignedLong(long val, int shift, char[] buf, int offset, int len) {
    int charPos = len;
    int radix = 1 &lt;&lt; shift;
    int mask = radix - 1;
    do {
    buf[offset + --charPos] = Integer.digits[((int) val) &amp; mask];
    val &gt;&gt;&gt;= shift;
    } while (val != 0 &amp;&amp; charPos &gt; 0);

    return charPos;
}</pre>
</div>
</div>
<div class="literalblock">
<div class="content">
<pre>public static String toString(long i) {
    if (i == Long.MIN_VALUE)
        return "-9223372036854775808";
    int size = (i &lt; 0) ? stringSize(-i) + 1 : stringSize(i);
    char[] buf = new char[size];
    getChars(i, size, buf);
    return new String(buf, true);
}

// 每次乘以10，比较大小，直到x小于定义p数，此时乘的次数就是x的位数。
static int stringSize(long x) {
    long p = 10;
    for (int i=1; i&lt;19; i++) {
        if (x &lt; p)
            return i;
        p = 10*p;
    }
    return 19;
}

static void getChars(long i, int index, char[] buf) {
    long q;
    int r;
    int charPos = index;
    char sign = 0;

    if (i &lt; 0) {
        sign = '-';
        i = -i;
    }

    while (i &gt; Integer.MAX_VALUE) {
        q = i / 100;
        // really: r = i - (q * 100);
        r = (int)(i - ((q &lt;&lt; 6) + (q &lt;&lt; 5) + (q &lt;&lt; 2)));
        i = q;
        buf[--charPos] = Integer.DigitOnes[r];
        buf[--charPos] = Integer.DigitTens[r];
    }

    int q2;
    int i2 = (int)i;
    while (i2 &gt;= 65536) {
        q2 = i2 / 100;
        // really: r = i2 - (q * 100);
        r = i2 - ((q2 &lt;&lt; 6) + (q2 &lt;&lt; 5) + (q2 &lt;&lt; 2));
        i2 = q2;
        buf[--charPos] = Integer.DigitOnes[r];
        buf[--charPos] = Integer.DigitTens[r];
    }

    for (;;) {
        q2 = (i2 * 52429) &gt;&gt;&gt; (16+3);
        r = i2 - ((q2 &lt;&lt; 3) + (q2 &lt;&lt; 1));  // r = i2-(q2*10) ...
        buf[--charPos] = Integer.digits[r];
        i2 = q2;
        if (i2 == 0) break;
        }
        if (sign != 0) {
        buf[--charPos] = sign;
    }
}</pre>
</div>
</div>
<div class="paragraph">
<p>这里对比Integer，可发现，多了一步，就是while (i &gt;
Integer.MAX_VALUE)，原理是一样的，就是把数的大小缩小到Integer的范围，再采用Integer的对应方法。</p>
</div>
<div class="paragraph">
<p><strong>字符串转long</strong></p>
</div>
<div class="literalblock">
<div class="content">
<pre>public static long parseLong(String s) throws NumberFormatException {
    return parseLong(s, 10);
}

public static long parseLong(String s, int radix) throws NumberFormatException {
    if (s == null) {
        throw new NumberFormatException("null");
    }

    if (radix &lt; Character.MIN_RADIX) {
        throw new NumberFormatException("radix " + radix + " less than Character.MIN_RADIX");
    }
    if (radix &gt; Character.MAX_RADIX) {
        throw new NumberFormatException("radix " + radix + " greater than Character.MAX_RADIX");
    }

    long result = 0;
    boolean negative = false;
    int i = 0, len = s.length();
    long limit = -Long.MAX_VALUE;
    long multmin;
    int digit;

    if (len &gt; 0) {
        char firstChar = s.charAt(0);
        if (firstChar &lt; '0') { // Possible leading "+" or "-"
            if (firstChar == '-') {
                negative = true;
                limit = Long.MIN_VALUE;
            } else if (firstChar != '+')
                throw NumberFormatException.forInputString(s);

            if (len == 1) // Cannot have lone "+" or "-"
                throw NumberFormatException.forInputString(s);
            i++;
        }

        multmin = limit / radix;
        while (i &lt; len) {
            // Accumulating negatively avoids surprises near MAX_VALUE
            digit = Character.digit(s.charAt(i++),radix);
            if (digit &lt; 0) {
                throw NumberFormatException.forInputString(s);
            }
            if (result &lt; multmin) {
                throw NumberFormatException.forInputString(s);
            }
            result *= radix;
            if (result &lt; limit + digit) {
                throw NumberFormatException.forInputString(s);
            }
            result -= digit;
        }
    } else {
        throw NumberFormatException.forInputString(s);
    }
    return negative ? result : -result;
}</pre>
</div>
</div>
<div class="literalblock">
<div class="content">
<pre>public static long parseUnsignedLong(String s) throws NumberFormatException {
    return parseUnsignedLong(s, 10);
}

    public static long parseUnsignedLong(String s, int radix)
                throws NumberFormatException {
        if (s == null)  {
            throw new NumberFormatException("null");
        }

        int len = s.length();
        if (len &gt; 0) {
            char firstChar = s.charAt(0);
            if (firstChar == '-') {
                throw new
                    NumberFormatException(String.format("Illegal leading minus sign " +
                                                       "on unsigned string %s.", s));
            } else {
                if (len &lt;= 12 || // Long.MAX_VALUE in Character.MAX_RADIX is 13 digits
                    (radix == 10 &amp;&amp; len &lt;= 18) ) { // Long.MAX_VALUE in base 10 is 19 digits
                    return parseLong(s, radix);
                }

                // No need for range checks on len due to testing above.
                long first = parseLong(s.substring(0, len - 1), radix);
                int second = Character.digit(s.charAt(len - 1), radix);
                if (second &lt; 0) {
                    throw new NumberFormatException("Bad digit at end of " + s);
                }
                long result = first * radix + second;
                if (compareUnsigned(result, first) &lt; 0) {
                    /*
                     * The maximum unsigned value, (2^64)-1, takes at
                     * most one more digit to represent than the
                     * maximum signed value, (2^63)-1.  Therefore,
                     * parsing (len - 1) digits will be appropriately
                     * in-range of the signed parsing.  In other
                     * words, if parsing (len -1) digits overflows
                     * signed parsing, parsing len digits will
                     * certainly overflow unsigned parsing.
                     *
                     * The compareUnsigned check above catches
                     * situations where an unsigned overflow occurs
                     * incorporating the contribution of the final
                     * digit.
                     */
                    throw new NumberFormatException(String.format("String value %s exceeds " +
                                                                  "range of unsigned long.", s));
                }
                return result;
            }
        } else {
            throw NumberFormatException.forInputString(s);
        }
    }</pre>
</div>
</div>
<div class="paragraph">
<p><strong>valueOf创建Long对象</strong></p>
</div>
<div class="literalblock">
<div class="content">
<pre>public static Long valueOf(String s, int radix) throws NumberFormatException {
    return Long.valueOf(parseLong(s, radix));
}</pre>
</div>
</div>
<div class="literalblock">
<div class="content">
<pre>public static Long valueOf(String s) throws NumberFormatException
{
    return Long.valueOf(parseLong(s, 10));
}</pre>
</div>
</div>
<div class="literalblock">
<div class="content">
<pre>public static Long valueOf(long l) {
    final int offset = 128;
    if (l &gt;= -128 &amp;&amp; l &lt;= 127) { // will cache
        return LongCache.cache[(int)l + offset];
    }
    return new Long(l);
}</pre>
</div>
</div>
<div class="paragraph">
<p><strong>decode方法</strong></p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java" data-lang="java">public static Long decode(String nm) throws NumberFormatException {
    int radix = 10;
    int index = 0;
    boolean negative = false;
    Long result;

    if (nm.length() == 0)
        throw new NumberFormatException("Zero length string");
    char firstChar = nm.charAt(0);
    // Handle sign, if present
    if (firstChar == '-') {
        negative = true;
        index++;
    } else if (firstChar == '+')
        index++;

    // Handle radix specifier, if present
    if (nm.startsWith("0x", index) || nm.startsWith("0X", index)) {
        index += 2;
        radix = 16;
    }
    else if (nm.startsWith("#", index)) {
        index ++;
        radix = 16;
    }
    else if (nm.startsWith("0", index) &amp;&amp; nm.length() &gt; 1 + index) {
        index ++;
        radix = 8;
    }

    if (nm.startsWith("-", index) || nm.startsWith("+", index))
        throw new NumberFormatException("Sign character in wrong position");

    try {
        result = Long.valueOf(nm.substring(index), radix);
        result = negative ? Long.valueOf(-result.longValue()) : result;
    } catch (NumberFormatException e) {
        // If number is Long.MIN_VALUE, we'll end up here. The next line
        // handles this case, and causes any genuine format error to be
        // rethrown.
        String constant = negative ? ("-" + nm.substring(index))
                                   : nm.substring(index);
        result = Long.valueOf(constant, radix);
    }
    return result;
}</code></pre>
</div>
</div>
<div class="paragraph">
<p><strong>构造器创建Long对象</strong></p>
</div>
<div class="literalblock">
<div class="content">
<pre>private final long value;

public Long(long value) {
    this.value = value;
}

public Long(String s) throws NumberFormatException {
    this.value = parseLong(s, 10);
}</pre>
</div>
</div>
<div class="paragraph">
<p><strong>继承Number类，数值转换</strong></p>
</div>
<div class="literalblock">
<div class="content">
<pre>public byte byteValue() {
    return (byte)value;
}

public short shortValue() {
    return (short)value;
}

public int intValue() {
    return (int)value;
}

public long longValue() {
    return value;
}

public float floatValue() {
    return (float)value;
}

public double doubleValue() {
    return (double)value;
}</pre>
</div>
</div>
<div class="paragraph">
<p><strong>hashCode以及equals方法</strong></p>
</div>
<div class="literalblock">
<div class="content">
<pre>@Override
public int hashCode() {
    return Long.hashCode(value);
}

public static int hashCode(long value) {
    return (int)(value ^ (value &gt;&gt;&gt; 32));
}

public boolean equals(Object obj) {
    if (obj instanceof Long) {
        return value == ((Long)obj).longValue();
    }
    return false;
}</pre>
</div>
</div>
<div class="paragraph">
<p><strong>getLong</strong></p>
</div>
<div class="paragraph">
<p>获取系统某个字符串属性代表的long值</p>
</div>
<div class="literalblock">
<div class="content">
<pre>public static Long getLong(String nm) {
    return getLong(nm, null);
}


public static Long getLong(String nm, long val) {
    Long result = Long.getLong(nm, null);
    return (result == null) ? Long.valueOf(val) : result;
}

public static Long getLong(String nm, Long val) {
    String v = null;
    try {
        v = System.getProperty(nm);
    } catch (IllegalArgumentException | NullPointerException e) {
    }
    if (v != null) {
        try {
            return Long.decode(v);
        } catch (NumberFormatException e) {
        }
    }
    return val;
}</pre>
</div>
</div>
<div class="paragraph">
<p><strong>比较</strong></p>
</div>
<div class="literalblock">
<div class="content">
<pre>public int compareTo(Long anotherLong) {
    return compare(this.value, anotherLong.value);
}

public static int compare(long x, long y) {
    return (x &lt; y) ? -1 : ((x == y) ? 0 : 1);
}

public static int compareUnsigned(long x, long y) {
    return compare(x + MIN_VALUE, y + MIN_VALUE);
}</pre>
</div>
</div>
<div class="paragraph">
<p><strong>运算 1.8 新增</strong></p>
</div>
<div class="literalblock">
<div class="content">
<pre>public static long divideUnsigned(long dividend, long divisor) {
    // 有符号比较
    if (divisor &lt; 0L) {
        // 根据被除数和除数的相对大小，答案必须是0或1。
        return (compareUnsigned(dividend, divisor)) &lt; 0 ? 0L :1L;
    }

    // 两个输入均为非负
    if (dividend &gt; 0)
        return dividend/divisor;
    else {
        /*
         * 对于简单代码，请使用BigInteger。直接以long操作的形式编写更长更快的代码是可能的；有关除法和余数算法，请参阅“Hacker's Delight”
         */
        return toUnsignedBigInteger(dividend).
            divide(toUnsignedBigInteger(divisor)).longValue();
    }
}</pre>
</div>
</div>
<div class="literalblock">
<div class="content">
<pre>public static long remainderUnsigned(long dividend, long divisor) {
    if (dividend &gt; 0 &amp;&amp; divisor &gt; 0) { // signed comparisons
        return dividend % divisor;
    } else {
        if (compareUnsigned(dividend, divisor) &lt; 0) // Avoid explicit check for 0 divisor
            return dividend;
        else
            return toUnsignedBigInteger(dividend).
                remainder(toUnsignedBigInteger(divisor)).longValue();
    }
}</pre>
</div>
</div>
<div class="literalblock">
<div class="content">
<pre>public static long sum(long a, long b) {
    return a + b;
}

public static long max(long a, long b) {
    return Math.max(a, b);
}

public static long min(long a, long b) {
    return Math.min(a, b);
}</pre>
</div>
</div>
<div class="paragraph">
<p><strong>其他方法</strong></p>
</div>
<div class="literalblock">
<div class="content">
<pre>// 取 i 这个数的二进制形式最左边的最高一位且高位后面全部补零，最后返回int型的结果。
// 给它传入一个数字，它将返回小于等于这个数字的一个2的幂次方数。
// https://www.cnblogs.com/nicerblog/p/11431181.html
public static long highestOneBit(long i) {
    // HD, Figure 3-1
    i |= (i &gt;&gt;  1);
    i |= (i &gt;&gt;  2);
    i |= (i &gt;&gt;  4);
    i |= (i &gt;&gt;  8);
    i |= (i &gt;&gt; 16);
    i |= (i &gt;&gt; 32);
    return i - (i &gt;&gt;&gt; 1);
}</pre>
</div>
</div>
<div class="literalblock">
<div class="content">
<pre>public static long lowestOneBit(long i) {
    // HD, Section 2-1
    return i &amp; -i;
}</pre>
</div>
</div>
<div class="literalblock">
<div class="content">
<pre>public static int numberOfLeadingZeros(long i) {
    // HD, Figure 5-6
     if (i == 0)
        return 64;
    int n = 1;
    int x = (int)(i &gt;&gt;&gt; 32);
    if (x == 0) { n += 32; x = (int)i; }
    if (x &gt;&gt;&gt; 16 == 0) { n += 16; x &lt;&lt;= 16; }
    if (x &gt;&gt;&gt; 24 == 0) { n +=  8; x &lt;&lt;=  8; }
    if (x &gt;&gt;&gt; 28 == 0) { n +=  4; x &lt;&lt;=  4; }
    if (x &gt;&gt;&gt; 30 == 0) { n +=  2; x &lt;&lt;=  2; }
    n -= x &gt;&gt;&gt; 31;
    return n;
}</pre>
</div>
</div>
<div class="literalblock">
<div class="content">
<pre>public static int numberOfTrailingZeros(long i) {
    // HD, Figure 5-14
    int x, y;
    if (i == 0) return 64;
    int n = 63;
    y = (int)i; if (y != 0) { n = n -32; x = y; } else x = (int)(i&gt;&gt;&gt;32);
    y = x &lt;&lt;16; if (y != 0) { n = n -16; x = y; }
    y = x &lt;&lt; 8; if (y != 0) { n = n - 8; x = y; }
    y = x &lt;&lt; 4; if (y != 0) { n = n - 4; x = y; }
    y = x &lt;&lt; 2; if (y != 0) { n = n - 2; x = y; }
    return n - ((x &lt;&lt; 1) &gt;&gt;&gt; 31);
}</pre>
</div>
</div>
<div class="literalblock">
<div class="content">
<pre>public static int bitCount(long i) {
   // HD, Figure 5-14
   i = i - ((i &gt;&gt;&gt; 1) &amp; 0x5555555555555555L);
   i = (i &amp; 0x3333333333333333L) + ((i &gt;&gt;&gt; 2) &amp; 0x3333333333333333L);
   i = (i + (i &gt;&gt;&gt; 4)) &amp; 0x0f0f0f0f0f0f0f0fL;
   i = i + (i &gt;&gt;&gt; 8);
   i = i + (i &gt;&gt;&gt; 16);
   i = i + (i &gt;&gt;&gt; 32);
   return (int)i &amp; 0x7f;
}</pre>
</div>
</div>
<div class="literalblock">
<div class="content">
<pre>public static long rotateRight(long i, int distance) {
    return (i &gt;&gt;&gt; distance) | (i &lt;&lt; -distance);
}</pre>
</div>
</div>
<div class="literalblock">
<div class="content">
<pre>public static long reverse(long i) {
    // HD, Figure 7-1
    i = (i &amp; 0x5555555555555555L) &lt;&lt; 1 | (i &gt;&gt;&gt; 1) &amp; 0x5555555555555555L;
    i = (i &amp; 0x3333333333333333L) &lt;&lt; 2 | (i &gt;&gt;&gt; 2) &amp; 0x3333333333333333L;
    i = (i &amp; 0x0f0f0f0f0f0f0f0fL) &lt;&lt; 4 | (i &gt;&gt;&gt; 4) &amp; 0x0f0f0f0f0f0f0f0fL;
    i = (i &amp; 0x00ff00ff00ff00ffL) &lt;&lt; 8 | (i &gt;&gt;&gt; 8) &amp; 0x00ff00ff00ff00ffL;
    i = (i &lt;&lt; 48) | ((i &amp; 0xffff0000L) &lt;&lt; 16) |
        ((i &gt;&gt;&gt; 16) &amp; 0xffff0000L) | (i &gt;&gt;&gt; 48);
    return i;
}</pre>
</div>
</div>
<div class="literalblock">
<div class="content">
<pre>public static long reverse(long i) {
    // HD, Figure 7-1
    i = (i &amp; 0x5555555555555555L) &lt;&lt; 1 | (i &gt;&gt;&gt; 1) &amp; 0x5555555555555555L;
    i = (i &amp; 0x3333333333333333L) &lt;&lt; 2 | (i &gt;&gt;&gt; 2) &amp; 0x3333333333333333L;
    i = (i &amp; 0x0f0f0f0f0f0f0f0fL) &lt;&lt; 4 | (i &gt;&gt;&gt; 4) &amp; 0x0f0f0f0f0f0f0f0fL;
    i = (i &amp; 0x00ff00ff00ff00ffL) &lt;&lt; 8 | (i &gt;&gt;&gt; 8) &amp; 0x00ff00ff00ff00ffL;
    i = (i &lt;&lt; 48) | ((i &amp; 0xffff0000L) &lt;&lt; 16) |
        ((i &gt;&gt;&gt; 16) &amp; 0xffff0000L) | (i &gt;&gt;&gt; 48);
    return i;
}</pre>
</div>
</div>
<div class="literalblock">
<div class="content">
<pre>public static long reverseBytes(long i) {
    i = (i &amp; 0x00ff00ff00ff00ffL) &lt;&lt; 8 | (i &gt;&gt;&gt; 8) &amp; 0x00ff00ff00ff00ffL;
    return (i &lt;&lt; 48) | ((i &amp; 0xffff0000L) &lt;&lt; 16) |
        ((i &gt;&gt;&gt; 16) &amp; 0xffff0000L) | (i &gt;&gt;&gt; 48);
}</pre>
</div>
</div>
<div class="literalblock">
<div class="content">
<pre>public static long reverseBytes(long i) {
    i = (i &amp; 0x00ff00ff00ff00ffL) &lt;&lt; 8 | (i &gt;&gt;&gt; 8) &amp; 0x00ff00ff00ff00ffL;
    return (i &lt;&lt; 48) | ((i &amp; 0xffff0000L) &lt;&lt; 16) |
        ((i &gt;&gt;&gt; 16) &amp; 0xffff0000L) | (i &gt;&gt;&gt; 48);
}</pre>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_short">1.10. Short</h3>
<div class="paragraph">
<p><strong>基本常量定义</strong></p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java" data-lang="java">    public static final short   MIN_VALUE = -32768;

    public static final short   MAX_VALUE = 32767;

    @SuppressWarnings("unchecked")
    public static final Class&lt;Short&gt;    TYPE = (Class&lt;Short&gt;) Class.getPrimitiveClass("short");

    public static final int SIZE = 16;

    public static final int BYTES = SIZE / Byte.SIZE;</code></pre>
</div>
</div>
<div class="paragraph">
<p><strong>构造器创建Short对象</strong></p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java" data-lang="java">    public Short(short value) {
        this.value = value;
    }
    public Short(String s) throws NumberFormatException {
        this.value = parseShort(s, 10);
    }</code></pre>
</div>
</div>
<div class="paragraph">
<p><strong>valueOf创建Short对象</strong></p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java" data-lang="java">    public static Short valueOf(String s, int radix)
        throws NumberFormatException {
        return valueOf(parseShort(s, radix));
    }
    public static Short valueOf(String s) throws NumberFormatException {
        return valueOf(s, 10);
    }
    public static Short valueOf(short s) {
        final int offset = 128;
        int sAsInt = s;
        if (sAsInt &gt;= -128 &amp;&amp; sAsInt &lt;= 127) { // must cache
            return ShortCache.cache[sAsInt + offset];
        }
        return new Short(s);
    }</code></pre>
</div>
</div>
<div class="paragraph">
<p><strong>字符串转short</strong></p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java" data-lang="java">    public static short parseShort(String s, int radix)
        throws NumberFormatException {
        int i = Integer.parseInt(s, radix);
        if (i &lt; MIN_VALUE || i &gt; MAX_VALUE)
            throw new NumberFormatException(
                "Value out of range. Value:\"" + s + "\" Radix:" + radix);
        return (short)i;
    }

    public static short parseShort(String s) throws NumberFormatException {
        return parseShort(s, 10);
    }</code></pre>
</div>
</div>
<div class="paragraph">
<p><strong>short转字符串</strong></p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java" data-lang="java">    public String toString() {
        return Integer.toString((int)value);
    }

    public static String toString(short s) {
        return Integer.toString((int)s, 10);
    }</code></pre>
</div>
</div>
<div class="paragraph">
<p><strong>继承Number类，数值之间转换</strong></p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java" data-lang="java">public byte byteValue() {
    return (byte)value;
}

public short shortValue() {
    return (short)value;
}

public int intValue() {
    return (int)value;
}

public long longValue() {
    return (long)value;
}

public float floatValue() {
    return (float)value;
}

public double doubleValue() {
    return value;
}</code></pre>
</div>
</div>
<div class="paragraph">
<p><strong>hashCode/equals/compare</strong></p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java" data-lang="java">    @Override
    public int hashCode() {
        return Short.hashCode(value);
    }

    public static int hashCode(short value) {
        return (int)value;
    }

    public boolean equals(Object obj) {
        if (obj instanceof Short) {
            return value == ((Short)obj).shortValue();
        }
        return false;
    }</code></pre>
</div>
</div>
<div class="paragraph">
<p><strong>其他方法</strong></p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java" data-lang="java">    public static Short decode(String nm) throws NumberFormatException {
        int i = Integer.decode(nm);
        if (i &lt; MIN_VALUE || i &gt; MAX_VALUE)
            throw new NumberFormatException(
                    "Value " + i + " out of range from input " + nm);
        return valueOf((short)i);
    }

    public static short reverseBytes(short i) {
        return (short) (((i &amp; 0xFF00) &gt;&gt; 8) | (i &lt;&lt; 8));
    }

    public static int toUnsignedInt(short x) {
        return ((int) x) &amp; 0xffff;
    }

    public static long toUnsignedLong(short x) {
        return ((long) x) &amp; 0xffffL;
    }</code></pre>
</div>
</div>
<div class="paragraph">
<p><strong>缓存</strong></p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java" data-lang="java">    private static class ShortCache {
        private ShortCache(){}

        static final Short cache[] = new Short[-(-128) + 127 + 1];

        static {
            for(int i = 0; i &lt; cache.length; i++)
                cache[i] = new Short((short)(i - 128));
        }
    }</code></pre>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_string">1.11. String</h3>
<div class="paragraph">
<p><strong>成员变量</strong></p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java" data-lang="java">    // 底层实现是一个char数组。
    private final char value[];

    private int hash; // Default to 0

    private static final long serialVersionUID = -6849794470754667710L;</code></pre>
</div>
</div>
<div class="paragraph">
<p><strong>通过构造器创建String对象</strong></p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java" data-lang="java">    public String() {
        this.value = "".value;
    }

    public String(String original) {
        this.value = original.value;
        this.hash = original.hash;
    }

   // 底层复制了一个char数组，修改旧的数组不会影响新创建的
    public String(char value[]) {
        this.value = Arrays.copyOf(value, value.length);
    }

   // offset即为char数组的下标，count是从下标开始字符个数。
    public String(char value[], int offset, int count) {
        if (offset &lt; 0) {
            throw new StringIndexOutOfBoundsException(offset);
        }
        if (count &lt;= 0) {
            if (count &lt; 0) {
                throw new StringIndexOutOfBoundsException(count);
            }
            if (offset &lt;= value.length) {
                this.value = "".value;
                return;
            }
        }
        // Note: offset or count might be near -1&gt;&gt;&gt;1.
    // value.length-count，是支持最大下标值，如果offset大于这个值，则会超长越界。
        if (offset &gt; value.length - count) {
            throw new StringIndexOutOfBoundsException(offset + count);
        }
    // 底层调用Arrays方法，查看Arrays源码
        this.value = Arrays.copyOfRange(value, offset, offset+count);
    }

    public String(int[] codePoints, int offset, int count) {
        if (offset &lt; 0) {
            throw new StringIndexOutOfBoundsException(offset);
        }
        if (count &lt;= 0) {
            if (count &lt; 0) {
                throw new StringIndexOutOfBoundsException(count);
            }
            if (offset &lt;= codePoints.length) {
                this.value = "".value;
                return;
            }
        }
        // Note: offset or count might be near -1&gt;&gt;&gt;1.
        if (offset &gt; codePoints.length - count) {
            throw new StringIndexOutOfBoundsException(offset + count);
        }

    // 最后一个字符下标
        final int end = offset + count;

        // Pass 1: Compute precise size of char[]
    // 计算出字符数组长度
        int n = count;
        for (int i = offset; i &lt; end; i++) {
            int c = codePoints[i];
            if (Character.isBmpCodePoint(c))
                continue;
        // 如果是增补字符，则采用2个char表示，这是定义。
            else if (Character.isValidCodePoint(c))
                n++;
            else throw new IllegalArgumentException(Integer.toString(c));
        }

        // Pass 2: Allocate and fill in char[]

        final char[] v = new char[n];
    // 这里i用来控制取值，j用来控制如果是增补字符，则需要2个位置，j一次循环需要自增2次。并调用Character方法存放增补字符。
        for (int i = offset, j = 0; i &lt; end; i++, j++) {
            int c = codePoints[i];
            if (Character.isBmpCodePoint(c))
                v[j] = (char)c;
            else
                Character.toSurrogates(c, v, j++);
        }

        this.value = v;
    }

    @Deprecated
    public String(byte ascii[], int hibyte) {
        this(ascii, hibyte, 0, ascii.length);
    }

    @Deprecated
    public String(byte ascii[], int hibyte, int offset, int count) {
        checkBounds(ascii, offset, count);
        char value[] = new char[count];

        if (hibyte == 0) {
            for (int i = count; i-- &gt; 0;) {
                value[i] = (char)(ascii[i + offset] &amp; 0xff);
            }
        } else {
            hibyte &lt;&lt;= 8;
            for (int i = count; i-- &gt; 0;) {
                value[i] = (char)(hibyte | (ascii[i + offset] &amp; 0xff));
            }
        }
        this.value = value;
    }

   // 底层使用StringCoding.decode，不做研究。
    public String(byte bytes[], int offset, int length, String charsetName)
            throws UnsupportedEncodingException {
        if (charsetName == null)
            throw new NullPointerException("charsetName");
        checkBounds(bytes, offset, length);
        this.value = StringCoding.decode(charsetName, bytes, offset, length);
    }

   // 底层使用StringCoding.decode，不做研究。
    public String(byte bytes[], int offset, int length, Charset charset) {
        if (charset == null)
            throw new NullPointerException("charset");
        checkBounds(bytes, offset, length);
        this.value =  StringCoding.decode(charset, bytes, offset, length);
    }

    public String(byte bytes[], String charsetName)
            throws UnsupportedEncodingException {
        this(bytes, 0, bytes.length, charsetName);
    }

    public String(byte bytes[], Charset charset) {
        this(bytes, 0, bytes.length, charset);
    }

    // 不指定字符集，默认是"ISO-8859-1"
    public String(byte bytes[], int offset, int length) {
        checkBounds(bytes, offset, length);
        this.value = StringCoding.decode(bytes, offset, length);
    }

    public String(byte bytes[]) {
        this(bytes, 0, bytes.length);
    }

    public String(StringBuffer buffer) {
        synchronized(buffer) {
            this.value = Arrays.copyOf(buffer.getValue(), buffer.length());
        }
    }

    public String(StringBuilder builder) {
        this.value = Arrays.copyOf(builder.getValue(), builder.length());
    }</code></pre>
</div>
</div>
<div class="paragraph">
<p><strong>对象方法</strong></p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java" data-lang="java">    public int length() {
        return value.length;
    }</code></pre>
</div>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java" data-lang="java">    public boolean isEmpty() {
        return value.length == 0;
    }</code></pre>
</div>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java" data-lang="java">    public char charAt(int index) {
        if ((index &lt; 0) || (index &gt;= value.length)) {
            throw new StringIndexOutOfBoundsException(index);
        }
        return value[index];
    }</code></pre>
</div>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java" data-lang="java">    public int codePointAt(int index) {
        if ((index &lt; 0) || (index &gt;= value.length)) {
            throw new StringIndexOutOfBoundsException(index);
        }
        return Character.codePointAtImpl(value, index, value.length);
    }</code></pre>
</div>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java" data-lang="java">    public int codePointBefore(int index) {
        int i = index - 1;
        if ((i &lt; 0) || (i &gt;= value.length)) {
            throw new StringIndexOutOfBoundsException(index);
        }
        return Character.codePointBeforeImpl(value, index, 0);
    }</code></pre>
</div>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java" data-lang="java">    public int codePointCount(int beginIndex, int endIndex) {
        if (beginIndex &lt; 0 || endIndex &gt; value.length || beginIndex &gt; endIndex) {
            throw new IndexOutOfBoundsException();
        }
        return Character.codePointCountImpl(value, beginIndex, endIndex - beginIndex);
    }

    public int offsetByCodePoints(int index, int codePointOffset) {
        if (index &lt; 0 || index &gt; value.length) {
            throw new IndexOutOfBoundsException();
        }
        return Character.offsetByCodePointsImpl(value, 0, value.length,
                index, codePointOffset);
    }</code></pre>
</div>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java" data-lang="java">    void getChars(char dst[], int dstBegin) {
        System.arraycopy(value, 0, dst, dstBegin, value.length);
    }

    public void getChars(int srcBegin, int srcEnd, char dst[], int dstBegin) {
        if (srcBegin &lt; 0) {
            throw new StringIndexOutOfBoundsException(srcBegin);
        }
        if (srcEnd &gt; value.length) {
            throw new StringIndexOutOfBoundsException(srcEnd);
        }
        if (srcBegin &gt; srcEnd) {
            throw new StringIndexOutOfBoundsException(srcEnd - srcBegin);
        }
        System.arraycopy(value, srcBegin, dst, dstBegin, srcEnd - srcBegin);
    }</code></pre>
</div>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java" data-lang="java">    public byte[] getBytes(String charsetName)
            throws UnsupportedEncodingException {
        if (charsetName == null) throw new NullPointerException();
        return StringCoding.encode(charsetName, value, 0, value.length);
    }

    public byte[] getBytes(Charset charset) {
        if (charset == null) throw new NullPointerException();
        return StringCoding.encode(charset, value, 0, value.length);
    }

    public byte[] getBytes() {
        return StringCoding.encode(value, 0, value.length);
    }</code></pre>
</div>
</div>
<div class="paragraph">
<p>比较地址，如果相等则字符串相等，其次比较字符串每个char的值是否相等。</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java" data-lang="java">    public boolean equals(Object anObject) {
        if (this == anObject) {
            return true;
        }
        if (anObject instanceof String) {
            String anotherString = (String)anObject;
            int n = value.length;
            if (n == anotherString.value.length) {
                char v1[] = value;
                char v2[] = anotherString.value;
                int i = 0;
                while (n-- != 0) {
                    if (v1[i] != v2[i])
                        return false;
                    i++;
                }
                return true;
            }
        }
        return false;
    }

    public boolean contentEquals(StringBuffer sb) {
        return contentEquals((CharSequence)sb);
    }

    // 注意，需要判断cs类型，如果是buffer，则需要加锁。
    public boolean contentEquals(CharSequence cs) {
        // Argument is a StringBuffer, StringBuilder
        if (cs instanceof AbstractStringBuilder) {
            if (cs instanceof StringBuffer) {
                synchronized(cs) {
                   return nonSyncContentEquals((AbstractStringBuilder)cs);
                }
            } else {
                return nonSyncContentEquals((AbstractStringBuilder)cs);
            }
        }
        // Argument is a String
        if (cs instanceof String) {
            return equals(cs);
        }
        // Argument is a generic CharSequence
        char v1[] = value;
        int n = v1.length;
        if (n != cs.length()) {
            return false;
        }
        for (int i = 0; i &lt; n; i++) {
            if (v1[i] != cs.charAt(i)) {
                return false;
            }
        }
        return true;
    }


    private boolean nonSyncContentEquals(AbstractStringBuilder sb) {
        char v1[] = value;
        char v2[] = sb.getValue();
        int n = v1.length;
        if (n != sb.length()) {
            return false;
        }
        for (int i = 0; i &lt; n; i++) {
            if (v1[i] != v2[i]) {
                return false;
            }
        }
        return true;
    }

    public boolean equalsIgnoreCase(String anotherString) {
        return (this == anotherString) ? true
                : (anotherString != null)
                &amp;&amp; (anotherString.value.length == value.length)
                &amp;&amp; regionMatches(true, 0, anotherString, 0, value.length);
    }</code></pre>
</div>
</div>
<div class="paragraph">
<p>指定一个范围段，进行char比较。</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java" data-lang="java">    public boolean regionMatches(int toffset, String other, int ooffset,
            int len) {
        char ta[] = value;
        int to = toffset;
        char pa[] = other.value;
        int po = ooffset;
        // Note: toffset, ooffset, or len might be near -1&gt;&gt;&gt;1.
        if ((ooffset &lt; 0) || (toffset &lt; 0)
                || (toffset &gt; (long)value.length - len)
                || (ooffset &gt; (long)other.value.length - len)) {
            return false;
        }
        while (len-- &gt; 0) {
            if (ta[to++] != pa[po++]) {
                return false;
            }
        }
        return true;
    }

    public boolean regionMatches(boolean ignoreCase, int toffset,
            String other, int ooffset, int len) {
        char ta[] = value;
        int to = toffset;
        char pa[] = other.value;
        int po = ooffset;
        // Note: toffset, ooffset, or len might be near -1&gt;&gt;&gt;1.
        if ((ooffset &lt; 0) || (toffset &lt; 0)
                || (toffset &gt; (long)value.length - len)
                || (ooffset &gt; (long)other.value.length - len)) {
            return false;
        }
        while (len-- &gt; 0) {
            char c1 = ta[to++];
            char c2 = pa[po++];
            if (c1 == c2) {
                continue;
            }
            if (ignoreCase) {
                // If characters don't match but case may be ignored,
                // try converting both characters to uppercase.
                // If the results match, then the comparison scan should
                // continue.
                char u1 = Character.toUpperCase(c1);
                char u2 = Character.toUpperCase(c2);
                if (u1 == u2) {
                    continue;
                }
                // Unfortunately, conversion to uppercase does not work properly
                // for the Georgian alphabet, which has strange rules about case
                // conversion.  So we need to make one last check before
                // exiting.
                if (Character.toLowerCase(u1) == Character.toLowerCase(u2)) {
                    continue;
                }
            }
            return false;
        }
        return true;
    }</code></pre>
</div>
</div>
<div class="paragraph">
<p>比较的是2个字符串char数组从头开始，不同字符的差值，如果有包含关系，则返回他们的长度差值。</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java" data-lang="java">    public int compareTo(String anotherString) {
        int len1 = value.length;
        int len2 = anotherString.value.length;
        int lim = Math.min(len1, len2);
        char v1[] = value;
        char v2[] = anotherString.value;

        int k = 0;
        while (k &lt; lim) {
            char c1 = v1[k];
            char c2 = v2[k];
            if (c1 != c2) {
                return c1 - c2;
            }
            k++;
        }
        return len1 - len2;
    }
    public int compareToIgnoreCase(String str) {
        return CASE_INSENSITIVE_ORDER.compare(this, str);
    }</code></pre>
</div>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java" data-lang="java">    public boolean startsWith(String prefix, int toffset) {
        char ta[] = value;
        int to = toffset;
        char pa[] = prefix.value;
        int po = 0;
        int pc = prefix.value.length;
        // Note: toffset might be near -1&gt;&gt;&gt;1.
        if ((toffset &lt; 0) || (toffset &gt; value.length - pc)) {
            return false;
        }
        while (--pc &gt;= 0) {
            if (ta[to++] != pa[po++]) {
                return false;
            }
        }
        return true;
    }

    public boolean startsWith(String prefix) {
        return startsWith(prefix, 0);
    }

    public boolean endsWith(String suffix) {
        return startsWith(suffix, value.length - suffix.value.length);
    }</code></pre>
</div>
</div>
<div class="paragraph">
<p>hash算法：s<em class="0">31^(n-1) + s[1]</em>31^(n-2) + … + s[n-1]</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java" data-lang="java">    public int hashCode() {
        int h = hash;
        if (h == 0 &amp;&amp; value.length &gt; 0) {
            char val[] = value;

            for (int i = 0; i &lt; value.length; i++) {
                h = 31 * h + val[i];
            }
            hash = h;
        }
        return h;
    }</code></pre>
</div>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java" data-lang="java">    public int indexOf(int ch) {
        return indexOf(ch, 0);
    }

    public int indexOf(int ch, int fromIndex) {
        final int max = value.length;
        if (fromIndex &lt; 0) {
            fromIndex = 0;
        } else if (fromIndex &gt;= max) {
            // Note: fromIndex might be near -1&gt;&gt;&gt;1.
            return -1;
        }

        if (ch &lt; Character.MIN_SUPPLEMENTARY_CODE_POINT) {
            // handle most cases here (ch is a BMP code point or a
            // negative value (invalid code point))
            final char[] value = this.value;
            for (int i = fromIndex; i &lt; max; i++) {
                if (value[i] == ch) {
                    return i;
                }
            }
            return -1;
        } else {
            return indexOfSupplementary(ch, fromIndex);
        }
    }

    private int indexOfSupplementary(int ch, int fromIndex) {
        if (Character.isValidCodePoint(ch)) {
            final char[] value = this.value;
            final char hi = Character.highSurrogate(ch);
            final char lo = Character.lowSurrogate(ch);
            final int max = value.length - 1;
            for (int i = fromIndex; i &lt; max; i++) {
                if (value[i] == hi &amp;&amp; value[i + 1] == lo) {
                    return i;
                }
            }
        }
        return -1;
    }

    public int indexOf(String str) {
        return indexOf(str, 0);
    }

    public int indexOf(String str, int fromIndex) {
        return indexOf(value, 0, value.length,
                str.value, 0, str.value.length, fromIndex);
    }
    static int indexOf(char[] source, int sourceOffset, int sourceCount,
            char[] target, int targetOffset, int targetCount,
            int fromIndex) {
    // 如果开始比较位置超出查找字符串长度，则判断目标字符串的长度
        if (fromIndex &gt;= sourceCount) {
            return (targetCount == 0 ? sourceCount : -1);
        }
        if (fromIndex &lt; 0) {
            fromIndex = 0;
        }
        if (targetCount == 0) {
            return fromIndex;
        }

        char first = target[targetOffset];
        int max = sourceOffset + (sourceCount - targetCount);

        for (int i = sourceOffset + fromIndex; i &lt;= max; i++) {
            // 找第一个相等的字符。这个while循环有趣。找到了才会结束while循环。
            if (source[i] != first) {
                while (++i &lt;= max &amp;&amp; source[i] != first);
            }

            // 找到第一个相同字符后，比较后面的字符。这里面的数组下标需要控制好。
            if (i &lt;= max) {
                int j = i + 1;
                int end = j + targetCount - 1;
                for (int k = targetOffset + 1; j &lt; end &amp;&amp; source[j]
                        == target[k]; j++, k++);

                if (j == end) {
                    /* Found whole string. */
                    return i - sourceOffset;
                }
            }
        }
        return -1;
    }</code></pre>
</div>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java" data-lang="java">    public int lastIndexOf(int ch) {
        return lastIndexOf(ch, value.length - 1);
    }

    public int lastIndexOf(int ch, int fromIndex) {
        if (ch &lt; Character.MIN_SUPPLEMENTARY_CODE_POINT) {
            // handle most cases here (ch is a BMP code point or a
            // negative value (invalid code point))
            final char[] value = this.value;
            int i = Math.min(fromIndex, value.length - 1);
            for (; i &gt;= 0; i--) {
                if (value[i] == ch) {
                    return i;
                }
            }
            return -1;
        } else {
            return lastIndexOfSupplementary(ch, fromIndex);
        }
    }

    private int lastIndexOfSupplementary(int ch, int fromIndex) {
        if (Character.isValidCodePoint(ch)) {
            final char[] value = this.value;
            char hi = Character.highSurrogate(ch);
            char lo = Character.lowSurrogate(ch);
            int i = Math.min(fromIndex, value.length - 2);
            for (; i &gt;= 0; i--) {
                if (value[i] == hi &amp;&amp; value[i + 1] == lo) {
                    return i;
                }
            }
        }
        return -1;
    }</code></pre>
</div>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java" data-lang="java">    public int lastIndexOf(String str) {
        return lastIndexOf(str, value.length);
    }
    public int lastIndexOf(String str, int fromIndex) {
        return lastIndexOf(value, 0, value.length,
                str.value, 0, str.value.length, fromIndex);
    }
    static int lastIndexOf(char[] source, int sourceOffset, int sourceCount,
            String target, int fromIndex) {
        return lastIndexOf(source, sourceOffset, sourceCount,
                       target.value, 0, target.value.length,
                       fromIndex);
    }

static int lastIndexOf(char[] source, int sourceOffset, int sourceCount,
            char[] target, int targetOffset, int targetCount,
            int fromIndex) {
        /*
         * Check arguments; return immediately where possible. For
         * consistency, don't check for null str.
         */
        int rightIndex = sourceCount - targetCount;
        if (fromIndex &lt; 0) {
            return -1;
        }
        if (fromIndex &gt; rightIndex) {
            fromIndex = rightIndex;
        }
        /* Empty string always matches. */
        if (targetCount == 0) {
            return fromIndex;
        }

        int strLastIndex = targetOffset + targetCount - 1;
        char strLastChar = target[strLastIndex];
        int min = sourceOffset + targetCount - 1;
        int i = min + fromIndex;

    startSearchForLastChar:
        while (true) {
            while (i &gt;= min &amp;&amp; source[i] != strLastChar) {
                i--;
            }
            if (i &lt; min) {
                return -1;
            }
            int j = i - 1;
            int start = j - (targetCount - 1);
            int k = strLastIndex - 1;

            while (j &gt; start) {
                if (source[j--] != target[k--]) {
                    i--;
                    continue startSearchForLastChar;
                }
            }
            return start - sourceOffset + 1;
        }
    }</code></pre>
</div>
</div>
<div class="paragraph">
<p><strong>单例，线程安全体现</strong></p>
</div>
<div class="paragraph">
<p>比较两个字符串的大小：从第一个字符开始比较，如果字符不同，则返回差值，如果一个字符串包含另一个字符串，则返回他们的长度差值。</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java" data-lang="java">    public static final Comparator&lt;String&gt; CASE_INSENSITIVE_ORDER
                                         = new CaseInsensitiveComparator();
    private static class CaseInsensitiveComparator
            implements Comparator&lt;String&gt;, java.io.Serializable {
        // use serialVersionUID from JDK 1.2.2 for interoperability
        private static final long serialVersionUID = 8575799808933029326L;

        public int compare(String s1, String s2) {
            int n1 = s1.length();
            int n2 = s2.length();
            int min = Math.min(n1, n2);
            for (int i = 0; i &lt; min; i++) {
                char c1 = s1.charAt(i);
                char c2 = s2.charAt(i);
                if (c1 != c2) {
                    c1 = Character.toUpperCase(c1);
                    c2 = Character.toUpperCase(c2);
                    if (c1 != c2) {
                        c1 = Character.toLowerCase(c1);
                        c2 = Character.toLowerCase(c2);
                        if (c1 != c2) {
                            // No overflow because of numeric promotion
                            return c1 - c2;
                        }
                    }
                }
            }
            return n1 - n2;
        }

        /** Replaces the de-serialized object. */
        private Object readResolve() { return CASE_INSENSITIVE_ORDER; }
    }</code></pre>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_jvm">1.12. JVM</h3>
<div class="paragraph">
<p><strong>java 结构图</strong></p>
</div>
<div class="imageblock">
<div class="content">
<img src="https://wanghengzhi.com/upload/2022/03/%E5%9B%BE%E7%89%87-95091800fc5e4e9a9b66ad69a541bbc9.png" alt="图片.png">
</div>
<div class="title">Figure 1. 图片.png</div>
</div>
<div class="ulist">
<ul>
<li>
<p>java基础语法</p>
</li>
<li>
<p>java工具，java、javac、jar、javap等</p>
</li>
<li>
<p>各种工具包，例如GUI、JDBC、java and util等各种针对不同环境提供的工具包</p>
</li>
<li>
<p>jvm 虚拟机，执行java字节码文件</p>
</li>
</ul>
</div>
<div class="paragraph">
<p><strong>java为何可以跨平台</strong></p>
</div>
<div class="paragraph">
<p>java文件编译成class文件，交由jvm进行解释运行，各个平台都有针对平台开发的jvm，相当于翻译，我们自需要完成业务逻辑，表达想法，至于在各个平台如何执行，则交由jvm这个翻译者来进行解释执行，所以说java是编译和解释共存的语言。jvm屏蔽了不同平台机器指令码和硬件的不同。</p>
</div>
<div class="paragraph">
<p><strong>jvm 调优思路</strong></p>
</div>
<div class="paragraph">
<p><strong>JVM 内存模型</strong></p>
</div>
<div class="imageblock">
<div class="content">
<img src="https://wanghengzhi.com/upload/2022/03/%E5%9B%BE%E7%89%87-458678ab00f14ae7a0fe9a2b67455997.png" alt="图片.png">
</div>
<div class="title">Figure 2. 图片.png</div>
</div>
<div class="quoteblock">
<blockquote>
<div class="paragraph">
<p>线程独享:
是指当线程开始执行代码时，创建的内存区域，只能此线程进行访问，主要是这些区域都是存放当前线程执行代码的一些内部数据。包含栈、本地方法栈、程序计数器</p>
</div>
</blockquote>
</div>
<div class="paragraph">
<p><strong>方法栈</strong></p>
</div>
<div class="paragraph">
<p>记录代码执行调用的顺序。采用栈结构 first in last out
，这种结构很适合代码执行，方法调用的先后顺序，外面的方法先执行后结束，里面的方法后执行先结束。每个栈帧即为一个方法的调用。</p>
</div>
<div class="paragraph">
<p>一个栈帧包含以下几个部分</p>
</div>
<div class="ulist">
<ul>
<li>
<p>局部变量表: 存放方法内部的局部变量</p>
</li>
<li>
<p>操作数栈：局部变量的操作，入栈出栈完成业务逻辑</p>
</li>
<li>
<p>动态链接：对其他方法的调用</p>
</li>
<li>
<p>方法出口：当此栈帧执行完成后，下一个执行位置，在调用此方法的时候，会记录上一个栈帧的位置，退出时，沿上一个栈帧记录的位置继续执行</p>
</li>
</ul>
</div>
<div class="paragraph">
<p><strong>本地方法栈</strong></p>
</div>
<div class="paragraph">
<p>类似于方法栈，针对的native方法。</p>
</div>
<div class="paragraph">
<p><strong>程序计数器</strong></p>
</div>
<div class="paragraph">
<p>用于记录线程执行位置，简单可视为行号，占用内存很少。</p>
</div>
<div class="quoteblock">
<blockquote>
<div class="paragraph">
<p>线程共享: 每一个线程都能访问到。</p>
</div>
</blockquote>
</div>
<div class="paragraph">
<p><strong>堆</strong></p>
</div>
<div class="paragraph">
<p>存放对象，创建的对象都存放在此区域中，此区域涉及到垃圾回收，当对象不再使用或者内存满了，会触发垃圾回收。</p>
</div>
<div class="paragraph">
<p><strong>元空间</strong></p>
</div>
<div class="paragraph">
<p>1.8之前是永久代，而且是堆中内存的一部分，1.8之后独立出来，使用直接内存，和基本实际内存关联，和jvm的内存无关。主要存放类信息以及常量、静态变量。</p>
</div>
<div class="paragraph">
<p><strong>垃圾回收机制</strong></p>
</div>
<div class="paragraph">
<p>当堆中的对象不再使用或者内存不够用时，会触发垃圾回收。堆中的内存分配，需根据实际
应用可以做调整，以便得到所谓的虚拟机调优。</p>
</div>
<div class="imageblock">
<div class="content">
<img src="https://wanghengzhi.com/upload/2022/03/%E5%9B%BE%E7%89%87-a14c1eb7e150401db0c001683ed9ffb8.png" alt="图片.png">
</div>
<div class="title">Figure 3. 图片.png</div>
</div>
<div class="paragraph">
<p><strong>新生代</strong></p>
</div>
<div class="paragraph">
<p>每次线程运行产生的对象都会现在eden区域进行存放，当新生代中的内存快满时，会触发minor
gc，存活的对象将会放在s0或s1区中的一个空白区域，另一个有对象的区域也会进行minor
gc,
并记录其分代年龄，当其年龄达到15时，将会放在老年代中。通过可达性算法来判断对象的有效性。</p>
</div>
<div class="paragraph">
<p><strong>老年代</strong></p>
</div>
<div class="paragraph">
<p><strong>gc如何判断垃圾</strong></p>
</div>
<div class="paragraph">
<p><strong>引用计数法</strong></p>
</div>
<div class="paragraph">
<p>每个对象都包含一个引用计数器，用于存放对其引用的次数，新增引用加1，引用失效减1，如果引用计数器大于0，表示对象还处于活跃状态，当引用为0时，意味着不再使用，标记可回收。</p>
</div>
<div class="paragraph">
<p>但是这样存在一个问题，
当两个对象相互引用时，可能出现引用计数器不为0，但实际已经是垃圾对象了。</p>
</div>
<div class="paragraph">
<p><strong>可达性算法</strong></p>
</div>
<div class="paragraph">
<p>以 GC root 为根节点，生成一个树状结构的引用。当GC root
不在使用，那么树状结构以下的都可标记为垃圾对象。</p>
</div>
<div class="paragraph">
<p>选定为根节点的条件</p>
</div>
<div class="ulist">
<ul>
<li>
<p>栈帧中本地变量表中对象</p>
</li>
<li>
<p>方法区，常量池引用的对象</p>
</li>
<li>
<p>加锁的对象（synchronized)</p>
</li>
<li>
<p>虚拟机内部需要用到的对象</p>
</li>
</ul>
</div>
<div class="paragraph">
<p><span class="image"><img src="https://wanghengzhi.com/upload/2022/03/%E5%9B%BE%E7%89%87-97ef6d5e89574ef6a0a114d2eb5590e3.png" alt="图片.png"></span>
<span class="image"><img src="https://wanghengzhi.com/upload/2022/03/%E5%9B%BE%E7%89%87-50706c842a074e05b339ed05a676ed47.png" alt="图片.png"></span></p>
</div>
<div class="paragraph">
<p><strong>jvm调优工具</strong></p>
</div>
<div class="paragraph">
<p><strong>jdk自带的 jvisualvm</strong></p>
</div>
<div class="paragraph">
<p>启动后，会显示一个可视化客户端，能检测出所有的jvm进程，选择指定进程就可以监控当前进程jvm的一个运行情况</p>
</div>
<div class="paragraph">
<p><strong>alibaba 开源的 arthas</strong></p>
</div>
<div class="paragraph">
<p>一个jar可执行文件，同理，启动后，会显示当前机器上所有的jvm线程，选择指定线程，可实时监控，并可根据不同的命令查找运行中出现的问题，用于定位。</p>
</div>
<div class="paragraph">
<p><strong>stw机制</strong></p>
</div>
<div class="paragraph">
<p>当进行垃圾回收时，会暂停所有的线程，也即 stop the world。</p>
</div>
<div class="paragraph">
<p>为什么要设计stw机制？</p>
</div>
<div class="paragraph">
<p>如果不引入stw机制，当程序在进行gc时，其他线程依旧执行，那么可以一个对象上一秒不是垃圾，由于线程执行完毕，下一刻就变成垃圾了，这是gc在对整个程序进行分析时，就会变得不准确，gc处理过于复杂，还不如暂停所有进程，等gc处理完毕后在恢复所有线程执行。目的就是保证在gc执行时，对象是否是垃圾的状态不可变，减少不确定性。</p>
</div>
<div class="paragraph">
<p><strong>jvm调优</strong></p>
</div>
<div class="paragraph">
<p>jvm调优，主要是减少stw的次数以及时间，避免频繁的进行full
gc，造成线程暂停，系统卡顿问题。</p>
</div>
<div class="paragraph">
<p>思路：</p>
</div>
<div class="ulist">
<ul>
<li>
<p>合理分配堆中的内存占用，例如正对频繁创建对象，但是对象用后即垃圾，可增大新生代Eden的内存，减少老年代的内存</p>
</li>
<li>
<p>提高minor
gc的频率，虽然次数增多，但是一次gc的时间很短，对用户影响要更小，相当于
10次 1s 的暂停优于 1次 10s的暂停</p>
</li>
</ul>
</div>
</div>
<div class="sect2">
<h3 id="_java_注解">1.13. Java 注解</h3>
<div class="sect3">
<h4 id="_什么是注解">1.13.1. 什么是注解</h4>
<div class="paragraph">
<p>Java 注解（Annotation），又称 Java 标注，是 JDK5.0
引入的一种注释机制。Java
语言中的类、方法、变量、参数和包等都可以被标注。</p>
</div>
<div class="paragraph">
<p>Java 语言中的类、方法、变量、参数和包等都可以被标注。和 Javadoc
不同，Java
标注可以通过反射获取标注内容。在编译器生成类文件时，标注可以被嵌入到字节码中。Java
虚拟机可以保留标注内容，在运行时可以获取到标注内容 。 当然它也支持自定义
Java 标注。</p>
</div>
<div class="paragraph">
<p>主要类都定义在 <code>java.lang.annotation</code> 包中。</p>
</div>
</div>
<div class="sect3">
<h4 id="_注解的作用">1.13.2. 注解的作用</h4>
<div class="ulist">
<ul>
<li>
<p>标记、提示作用，例如 @Deprecated 标记某个类或方法不推荐使用，本身对代码无任何影响。
-</p>
</li>
</ul>
</div>
</div>
<div class="sect3">
<h4 id="_注解的组成">1.13.3. 注解的组成</h4>
<div class="paragraph">
<p>java Annotation 的组成中，有 3 个非常重要的主干类。</p>
</div>
<div class="olist arabic">
<ol class="arabic">
<li>
<p>Annotation.java
这是所有注解的父类。类似于所有对象都默认实现Object.java类。具体可查看Annotation.java的源码说明。</p>
</li>
<li>
<p>ElementType.java 这个枚举类定义了注解的出现位置（可以选择多个）。</p>
</li>
<li>
<p>RetentionPolicy.java 这个枚举类定义了注解的生存期间（只能选择一个）。</p>
</li>
</ol>
</div>
</div>
<div class="sect3">
<h4 id="_自定义注解">1.13.4. 自定义注解</h4>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java" data-lang="java">package world.wangxiao.learn.java.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @author wangxiao
 */
@Retention(RetentionPolicy.CLASS)
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface MyAnnotation {

}</code></pre>
</div>
</div>
<div class="olist arabic">
<ol class="arabic">
<li>
<p>使用 @interface 定义，从编译文件中可知道注解实际属于接口，但无法
`implements`其他类</p>
</li>
<li>
<p>通过@Retention 以及 RetentionPolicy.java 标记定义注解的生存期间</p>
</li>
<li>
<p>通过@Target以及 ElementType.java
标记定义注解的存在位置（Type:类，METHOD: 方法）</p>
</li>
</ol>
</div>
</div>
<div class="sect3">
<h4 id="_注解的使用">1.13.5. 注解的使用</h4>
<div class="paragraph">
<p>注解的使用位置和定义注解时 @Target 标注的位置有关。</p>
</div>
<div class="paragraph">
<p>例如MyAnnotation只能用于类和方法头部：</p>
</div>
<div class="literalblock">
<div class="content">
<pre>package world.wangxiao.learn.java.annotation;

/**
 * @author wangxiao
 */
@MyAnnotation
public class AnnotationTest {

    @MyAnnotation
    public void test1() {

    }
}</pre>
</div>
</div>
</div>
<div class="sect3">
<h4 id="_在注解中定义抽象方法">1.13.6. 在注解中定义抽象方法</h4>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java" data-lang="java">package world.wangxiao.learn.java.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @author wangxiao
 */
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface MyAnnotation {

    int m1() default 0;

    String m2() default "hello";

    String m3();

}</code></pre>
</div>
</div>
<div class="olist arabic">
<ol class="arabic">
<li>
<p>返回值类型不能是 void 以及基本数据类型的包装类</p>
</li>
<li>
<p>没有 default 值时，使用该注解需要显示调用方法，见下面代码</p>
</li>
</ol>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java" data-lang="java">package world.wangxiao.learn.java.annotation;

/**
 * @author wangxiao
 */
@MyAnnotation(m3 = "xx")
public class AnnotationTest {

    @MyAnnotation(m3 = "xx")
    public void test1() {

    }
}</code></pre>
</div>
</div>
</div>
<div class="sect3">
<h4 id="_注解的应用场景">1.13.7. 注解的应用场景</h4>
<div class="olist arabic">
<ol class="arabic">
<li>
<p>编译检查，注意通过编译器给出错误提示。</p>
<div class="olist loweralpha">
<ol class="loweralpha" type="a">
<li>
<p>@Override，如果有方法被@Override 标示，但父类中却没有”被 @Override
标注”的同名方法，则编译器会报错。</p>
</li>
<li>
<p>@Deprecated，编译器会使用中划线标识出该函数。</p>
</li>
</ol>
</div>
</li>
<li>
<p>通过给 Annotation 注解加上 @Documented 标签，能使该 Annotation
标签出现在 javadoc 中。</p>
</li>
<li>
<p>在反射的 Class, Method, Field 等函数中，有许多于 Annotation
相关的接口。（重点，spring框架很多功能都是结合注解以及反射来实现的）</p>
</li>
<li>
<p>通过 @Override, @Deprecated 等，我们能很方便的了解程序的大致结构。</p>
</li>
</ol>
</div>
</div>
<div class="sect3">
<h4 id="_注解作用范围">1.13.8. 注解作用范围</h4>
<div class="paragraph">
<p>注解的作用范围定义在 ElementType.java 中</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java" data-lang="java">public enum ElementType {
    /** 类、接口（包含注解）、枚举 */
    TYPE,

    /** 字段（包含枚举字段） */
    FIELD,

    /** 方法 */
    METHOD,

    /** 参数 */
    PARAMETER,

    /** 构造器 */
    CONSTRUCTOR,

    /** 本地变量 */
    LOCAL_VARIABLE,

    /** 注解类型 */
    ANNOTATION_TYPE,

    /** 包 */
    PACKAGE,

    /**
     * Type parameter declaration
     *
     * @since 1.8
     */
    TYPE_PARAMETER,

    /**
     * Use of a type
     *
     * @since 1.8
     */
    TYPE_USE
}</code></pre>
</div>
</div>
</div>
<div class="sect3">
<h4 id="_结合_target_注解使用">1.13.9. 结合 Target 注解使用</h4>
<div class="literalblock">
<div class="content">
<pre>@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {
    /**
     * 返回值是一个数组，所以可以定义多个使用范围
     */
    ElementType[] value();
}</pre>
</div>
</div>
</div>
<div class="sect3">
<h4 id="_生存范围">1.13.10. 生存范围</h4>
<div class="paragraph">
<p>定义在 RetentionPolicy.java 类中</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java" data-lang="java">package java.lang.annotation;

public enum RetentionPolicy {
    // 只存在于源代码中，会被编译器抛弃
    SOURCE,

    // 能被编译器编译到class文件中，但是无法被虚拟机所检测到。默认行为。
    CLASS,

    //  能被编译器编译到class文件中，且能被虚拟机所检测到
    RUNTIME
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>配合 Rention 注解使用</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java" data-lang="java">@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
    // 返回值为RetentionPolicy，只能有一个。
    RetentionPolicy value();
}</code></pre>
</div>
</div>
</div>
<div class="sect3">
<h4 id="_jdk_常用注解">1.13.11. JDK 常用注解</h4>
<div class="sect4">
<h5 id="__deprecated">1.13.11.1. @Deprecated</h5>
<div class="paragraph">
<p>@Deprecated 所标注内容，不再被建议使用。在类上加则表示整个类不推荐使用，在方法上加，则表示方法不推荐使用。如果我们使用这个注解标记类或者方法，一定要指明新的替代类或者方法。</p>
</div>
</div>
<div class="sect4">
<h5 id="__override">1.13.11.2. @Override</h5>
<div class="paragraph">
<p>@Override 只能标注方法，表示该方法覆盖父类中的方法。</p>
</div>
</div>
<div class="sect4">
<h5 id="__documented">1.13.11.3. @Documented</h5>
<div class="paragraph">
<p>@Documented 所标注内容，可以出现在javadoc中。</p>
</div>
</div>
<div class="sect4">
<h5 id="__inherited">1.13.11.4. @Inherited</h5>
<div class="paragraph">
<p>@Inherited只能被用来标注"`Annotation类型`"，它所标注的Annotation具有继承性。</p>
</div>
</div>
<div class="sect4">
<h5 id="__retention">1.13.11.5. @Retention</h5>
<div class="paragraph">
<p>@Retention只能被用来标注"`Annotation类型`"，而且它被用来指定Annotation的RetentionPolicy属性。</p>
</div>
</div>
<div class="sect4">
<h5 id="__target">1.13.11.6. @Target</h5>
<div class="paragraph">
<p>@Target只能被用来标注"`Annotation类型`"，而且它被用来指定Annotation的ElementType属性。</p>
</div>
</div>
<div class="sect4">
<h5 id="__suppresswarnings">1.13.11.7. @SuppressWarnings</h5>
<div class="paragraph">
<p>@SuppressWarnings 所标注内容产生的警告，编译器会对这些警告保持静默。</p>
</div>
<div class="literalblock">
<div class="content">
<pre>deprecation  -- 使用了不赞成使用的类或方法时的警告
unchecked    -- 执行了未检查的转换时的警告，例如当使用集合时没有用泛型 (Generics) 来指定集合保存的类型。
fallthrough  -- 当 Switch 程序块直接通往下一种情况而没有 Break 时的警告。
path         -- 在类路径、源文件路径等中有不存在的路径时的警告。
serial       -- 当在可序列化的类上缺少 serialVersionUID 定义时的警告。
finally      -- 任何 finally 子句不能正常完成时的警告。
all          -- 关于以上所有情况的警告。
SpellCheckingInspection -- idea 拼写错误。</pre>
</div>
</div>
<div class="paragraph">
<p>例如，如果方法中调用了一个被申明已废弃的方法，编辑器会显示中划线，在方法头部加上<em>@SuppressWarnings(value=\{&#8220;deprecation&#8221;})</em>，中划线就会消失。</p>
</div>
</div>
</div>
<div class="sect3">
<h4 id="_感悟">1.13.12. 感悟</h4>
<div class="paragraph">
<p>注解需要配合反射来实现很多逻辑功能。可看作为一种标记，程序运行时，可以通过反射查找需要的标记，然后获取信息，完成很多功能。</p>
</div>
<div class="paragraph">
<p>参考：https://www.runoob.com/w3cnote/java-annotation.html</p>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_stream_流系列">1.14. Stream 流系列</h3>
<div class="paragraph">
<p>参考：</p>
</div>
<div class="paragraph">
<p><a href="https://www.cnblogs.com/CarpenterLee/p/6637118.html" class="bare">https://www.cnblogs.com/CarpenterLee/p/6637118.html</a></p>
</div>
<div class="paragraph">
<p><a href="https://blog.csdn.net/y_k_y/article/details/84633001" class="bare">https://blog.csdn.net/y_k_y/article/details/84633001</a></p>
</div>
<div class="paragraph">
<p><a href="https://zhuanlan.zhihu.com/p/31220388" class="bare">https://zhuanlan.zhihu.com/p/31220388</a></p>
</div>
<div class="paragraph">
<p><a href="https://segmentfault.com/a/1190000009270758" class="bare">https://segmentfault.com/a/1190000009270758</a></p>
</div>
<div class="paragraph">
<p>学习研究心得体会</p>
</div>
<div class="paragraph">
<p><strong>为何要提出流的概念？</strong></p>
</div>
<div class="quoteblock">
<blockquote>
<div class="paragraph">
<p>Lambda 表达式使流的实现成为了可能。</p>
</div>
</blockquote>
</div>
<div class="paragraph">
<p>在Stream以前，我们查询一个集合中的某个或某类元素，我们会使用常规for循环，再在循环体内，进行if、else判断，依次或多次，最终得到我们的结果。</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java" data-lang="java">int longest = 0;
for(String str : strings){
    if(str.startsWith("A")){// 1. filter(), 保留以A开头的字符串
        int len = str.length();// 2. mapToInt(), 转换成长度
        longest = Math.max(len, longest);// 3. max(), 保留最长的长度
    }
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>使用流后：</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java" data-lang="java">int longestStringLengthStartingWithA
        = strings.stream()
              .filter(s -&gt; s.startsWith("A"))
              .mapToInt(String::length)
              .max();</code></pre>
</div>
</div>
<div class="paragraph">
<p>前后对比可以看出：</p>
</div>
<div class="ulist">
<ul>
<li>
<p>filter 对应 if 判断</p>
</li>
<li>
<p>mapToInt 对应 str.length</p>
</li>
<li>
<p>max 对应 Max.max</p>
</li>
<li>
<p>每一个操作，都会产生一个流，链式调用产生一个双向链表流。</p>
</li>
<li>
<p>流的每一步操作实际就是将原本的功能代码，转为Lambda表达式，传递给流，让流来帮我们进行计算，并返回相应的结果。</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>效果图：</p>
</div>
<div class="imageblock">
<div class="content">
<img src="http://www.wanghengzhi.com/upload/2021/08/%E5%9B%BE%E7%89%87-6afdd9c2450f44f0a11b795e0a6be19e.png" alt="图片.png">
</div>
<div class="title">Figure 4. 图片.png</div>
</div>
<div class="paragraph">
<p>结论（个人看法）：在一堆数据中，进行筛选或其他操作，可多步，最终得到想要的结果。而每一步操作都可视为模板代码，例如if判断，去重这些。而流的创建就是为了简化、消除这些模板代码。</p>
</div>
<div class="paragraph">
<p><strong>一个完整的链路流包含3个部分：源头 —&gt; 处理过程（多个） —&gt; 结果</strong></p>
</div>
<div class="paragraph">
<p>Stream 和 Pipeline 的关系：</p>
</div>
<div class="paragraph">
<p>Pipleline为Stream的具体实现，一个完整的链路流，包含多个Pipleline，也即多个Stream组成。</p>
</div>
<div class="paragraph">
<p><strong>实例分析</strong></p>
</div>
<div class="paragraph">
<p>需求：从一群学生中找到符合要求的学生名字集合</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java" data-lang="java">    public static void main(String[] args) {
        List&lt;Student&gt; objects = new ArrayList&lt;&gt;();
    // 学号id、年龄age、性别sex、姓名name
        objects.add(new Student(2, 15, true, "小明"));
        objects.add(new Student(1, 16, false, "小红"));
        objects.add(new Student(5, 15, false, "小芳"));
        objects.add(new Student(4, 16, false, "小花"));
        objects.add(new Student(6, 15, false, "小爱"));
        objects.add(new Student(3, 18, true, "小新"));

        Stream&lt;Student&gt; stream1 = objects.stream();
        Stream&lt;Student&gt; stream2 = stream1.skip(2);
        Stream&lt;Student&gt; stream3 = stream2.filter(e -&gt; e.getAge() &gt; 15);
        Stream&lt;Student&gt; stream4 = stream3.sorted(Comparator.comparing(Student::getAge));
        Stream&lt;String&gt; stream5 = stream4.map(Student::getName);
        Stream&lt;String&gt; stream6 = stream5.distinct();
        List&lt;String&gt; collect = stream6.collect(Collectors.toList());
    }</code></pre>
</div>
</div>
<div class="paragraph">
<p>这里没有采用链式调用，而是常规定义出各个操作时的流，便于debug查看元素组成。</p>
</div>
<div class="paragraph">
<p><strong>如何生成双向链表流：</strong></p>
</div>
<div class="olist arabic">
<ol class="arabic">
<li>
<p>当debug走过stream1流时，查看源码可知，底层创建了一个ReferencePipelin$Head对象流:</p>
</li>
</ol>
</div>
<div class="imageblock">
<div class="content">
<img src="http://www.wanghengzhi.com/upload/2021/08/%E5%9B%BE%E7%89%87-caf122ed806b4e9cbc5e007f5f204da8.png" alt="图片.png">
</div>
<div class="title">Figure 5. 图片.png</div>
</div>
<div class="olist arabic">
<ol class="arabic" start="2">
<li>
<p>当debug走过stream2流时，查看源码可知，底层使用SliceOps创建了一个ReferencePipeline.StatelessOp流:</p>
</li>
</ol>
</div>
<div class="imageblock">
<div class="content">
<img src="http://www.wanghengzhi.com/upload/2021/08/%E5%9B%BE%E7%89%87-19942f29dc0b4577ac76c5d1fd31fc8f.png" alt="图片.png">
</div>
<div class="title">Figure 6. 图片.png</div>
</div>
<div class="olist arabic">
<ol class="arabic" start="3">
<li>
<p>当debug走过stream3流时，底层创建了一个ReferencePipeline.StatefulOp流</p>
</li>
</ol>
</div>
<div class="imageblock">
<div class="content">
<img src="http://www.wanghengzhi.com/upload/2021/08/%E5%9B%BE%E7%89%87-550a1d90eede45eea5e3c7ddbc2f626e.png" alt="图片.png">
</div>
<div class="title">Figure 7. 图片.png</div>
</div>
<div class="olist arabic">
<ol class="arabic" start="4">
<li>
<p>当debug走过stream4流时，查看源码可知，底层使用SortedOps创建了一个ReferencePipeline.StatelessOp流:</p>
</li>
</ol>
</div>
<div class="imageblock">
<div class="content">
<img src="http://www.wanghengzhi.com/upload/2021/08/%E5%9B%BE%E7%89%87-f4c20df999b64733a2db94d85f07965b.png" alt="图片.png">
</div>
<div class="title">Figure 8. 图片.png</div>
</div>
<div class="olist arabic">
<ol class="arabic" start="5">
<li>
<p>当debug走过stream5流时，查看源码可知，底层使用SortedOps创建了一个ReferencePipeline.StatefulOp流:</p>
</li>
</ol>
</div>
<div class="imageblock">
<div class="content">
<img src="http://www.wanghengzhi.com/upload/2021/08/%E5%9B%BE%E7%89%87-012a12ef4e9241ad9ed110a00a1aa3f5.png" alt="图片.png">
</div>
<div class="title">Figure 9. 图片.png</div>
</div>
<div class="olist arabic">
<ol class="arabic" start="6">
<li>
<p>当debug走过stream6流时，查看源码可知，底层使用SortedOps创建了一个ReferencePipeline.StatelessOp流:</p>
</li>
</ol>
</div>
<div class="imageblock">
<div class="content">
<img src="http://www.wanghengzhi.com/upload/2021/08/%E5%9B%BE%E7%89%87-9f49126daade4162b18b03edd8987a61.png" alt="图片.png">
</div>
<div class="title">Figure 10. 图片.png</div>
</div>
<div class="olist arabic">
<ol class="arabic" start="7">
<li>
<p>当debug走过collect时：</p>
</li>
</ol>
</div>
<div class="imageblock">
<div class="content">
<img src="http://www.wanghengzhi.com/upload/2021/08/%E5%9B%BE%E7%89%87-230712d5c5424cd6b257de69b4ac24b6.png" alt="图片.png">
</div>
<div class="title">Figure 11. 图片.png</div>
</div>
<div class="paragraph">
<p>每走一步，可以单步进入方法内部，会发现每一个stage操作中，只包含创建对象。在collect之前，完全是在创建各种流，并且流承上启下，其中关键字段为previousStage、nextStage、depth以及linkedOrConsumed。当使用上一个流产生新的流时，就会将上一个流赋值给下一个流的previousStage，并且linkedOrConsued设置为true，可无限调用，直到一个结束动作（例如collect)。</p>
</div>
<div class="ulist">
<ul>
<li>
<p>其结构就是一个双向链表，previousStage和nextStage连接前后流，Head只有nextStage，无previousStage。</p>
</li>
<li>
<p>depth标示这个元素处于index位置（从0开始）。在结束操作中，会根据这个depth循环遍历每一个节点。</p>
</li>
<li>
<p>linkedOrConsumed，查看其源码，可知如果流被引用后，这个流就不能再次使用了。原因很简单，这个流被使用了，处于某个链表结构中，如果再被其他的流引用，可能会导致流的改变，从而改变原来链表的结果，因此，流一旦被使用就不能被修改了。</p>
</li>
</ul>
</div>
<div class="paragraph">
<p><strong>最终结构如下：</strong>
<span class="image"><img src="http://www.wanghengzhi.com/upload/2021/08/%E5%9B%BE%E7%89%87-84274aba6f534d6abc34cac92bc95885.png" alt="图片.png"></span></p>
</div>
<div class="paragraph">
<p><strong>如何处理数据</strong></p>
</div>
<div class="paragraph">
<p><strong>目前为止，我们知道了，一个完整的流包含3个过程，Head流、中间操作stage（多个）以及一个结束操作，并且创建流链表没做任何业务处理，可知结束操作一定会通过创建的链表流来进行一系列的操作，下面就具体分析下`collect`，看看这个方法做了什么？</strong></p>
</div>
<div class="paragraph">
<p><strong>先看参数：<code>Collectors.toList()</code>：</strong></p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java" data-lang="java">    public static &lt;T&gt;
    Collector&lt;T, ?, List&lt;T&gt;&gt; toList() {
        return new CollectorImpl&lt;&gt;((Supplier&lt;List&lt;T&gt;&gt;) ArrayList::new, List::add,
                                   (left, right) -&gt; { left.addAll(right); return left; },
                                   CH_ID);
    }</code></pre>
</div>
</div>
<div class="paragraph">
<p>创建了一个CollectorImpl对象，有参构造器由四个参数组成：</p>
</div>
<div class="ulist">
<ul>
<li>
<p><code>Supplier&lt;A&gt; supplier</code></p>
</li>
<li>
<p><code>BiConsumer&lt;A, T&gt; accumulator</code></p>
</li>
<li>
<p><code>BinaryOperator&lt;A&gt; combiner</code></p>
</li>
<li>
<p><code>Set&lt;Characteristics&gt; characteristics</code></p>
</li>
</ul>
</div>
<div class="paragraph">
<p><strong>接着进入collect方法中：</strong></p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java" data-lang="java">    @Override
    @SuppressWarnings("unchecked")
    public final &lt;R, A&gt; R collect(Collector&lt;? super P_OUT, A, R&gt; collector) {
        A container;
        if (isParallel()
                &amp;&amp; (collector.characteristics().contains(Collector.Characteristics.CONCURRENT))
                &amp;&amp; (!isOrdered() || collector.characteristics().contains(Collector.Characteristics.UNORDERED))) {
            container = collector.supplier().get();
            BiConsumer&lt;A, ? super P_OUT&gt; accumulator = collector.accumulator();
            forEach(u -&gt; accumulator.accept(container, u));
        }
        else {
            container = evaluate(ReduceOps.makeRef(collector));
        }
        return collector.characteristics().contains(Collector.Characteristics.IDENTITY_FINISH)
               ? (R) container
               : collector.finisher().apply(container);
    }</code></pre>
</div>
</div>
<div class="ulist">
<ul>
<li>
<p>这里 collector 参数即为Collectors.toList()创建的对象，由此可知泛型参数
？super P_OUT 指元素类型（这里时String），A 代表一个List，R代表</p>
</li>
<li>
<p>A container:</p>
</li>
<li>
<p>第一个if：当时平行流时，处理。 todo:如何处理？</p>
</li>
<li>
<p>else: 串行处理流，本例就是这里进行处理，可知调用了一个evaluate方法。</p>
</li>
<li>
<p>return: todo</p>
</li>
</ul>
</div>
<div class="paragraph">
<p><strong>ReduceOps.makeRef(collector)：</strong></p>
</div>
<div class="paragraph">
<p>实质创建了 <code>ReduceOp</code> 匿名对象：</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java" data-lang="java">    public static &lt;T, I&gt; TerminalOp&lt;T, I&gt;
    makeRef(Collector&lt;? super T, I, ?&gt; collector) {
        Supplier&lt;I&gt; supplier = Objects.requireNonNull(collector).supplier();
        BiConsumer&lt;I, ? super T&gt; accumulator = collector.accumulator();
        BinaryOperator&lt;I&gt; combiner = collector.combiner();
        class ReducingSink extends Box&lt;I&gt;
                implements AccumulatingSink&lt;T, I, ReducingSink&gt; {
            @Override
            public void begin(long size) {
                state = supplier.get();
            }

            @Override
            public void accept(T t) {
                accumulator.accept(state, t);
            }

            @Override
            public void combine(ReducingSink other) {
                state = combiner.apply(state, other.state);
            }
        }
        return new ReduceOp&lt;T, I, ReducingSink&gt;(StreamShape.REFERENCE) {
            @Override
            public ReducingSink makeSink() {
                return new ReducingSink();
            }

            @Override
            public int getOpFlags() {
                return collector.characteristics().contains(Collector.Characteristics.UNORDERED)
                       ? StreamOpFlag.NOT_ORDERED
                       : 0;
            }
        };
    }</code></pre>
</div>
</div>
<div class="ulist">
<ul>
<li>
<p>这里创建了一个局部内部类ReducingSink，继承Box&lt;I&gt;，这个Box要留意一下。</p>
</li>
<li>
<p>return 了一个 <code>ReduceOp</code>
匿名对象，其中从写了makeSink方法，返回了一个局部内部内对象。</p>
</li>
</ul>
</div>
<div class="paragraph">
<p><strong>evaluate 方法：</strong></p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java" data-lang="java">    final &lt;R&gt; R evaluate(TerminalOp&lt;E_OUT, R&gt; terminalOp) {
        assert getOutputShape() == terminalOp.inputShape();
        if (linkedOrConsumed)
            throw new IllegalStateException(MSG_STREAM_LINKED);
        linkedOrConsumed = true;

        return isParallel()
               ? terminalOp.evaluateParallel(this, sourceSpliterator(terminalOp.getOpFlags()))
               : terminalOp.evaluateSequential(this, sourceSpliterator(terminalOp.getOpFlags()));
    }</code></pre>
</div>
</div>
<div class="ulist">
<ul>
<li>
<p>这里参数 terminalOp 也即上一步创建的 <code>ReduceOp</code> 匿名对象</p>
</li>
<li>
<p>assert 判断这个流的 StreamShape 一定要等于 terminalOp 对象里面的
StreamShape，需要保持一致。</p>
</li>
<li>
<p>if 判断，同理，如果这个流被使用了，就不能再次使用了。这里的流指的时
collect 操作前一个流。</p>
</li>
<li>
<p>isParallel()： 平行流还是串行流，也即多线程还是单线程处理。</p>
</li>
<li>
<p>这里是单线程，terminalOp.evaluateSequential</p>
</li>
</ul>
</div>
<div class="paragraph">
<p><strong>继续 <code>terminalOp.evaluateSequential</code></strong></p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java" data-lang="java">        @Override
        public &lt;P_IN&gt; R evaluateSequential(PipelineHelper&lt;T&gt; helper,
                                           Spliterator&lt;P_IN&gt; spliterator) {
            return helper.wrapAndCopyInto(makeSink(), spliterator).get();
        }</code></pre>
</div>
</div>
<div class="ulist">
<ul>
<li>
<p>这里有个关键 makeSink(), 也即调用了前面 <code>ReduceOp</code>
匿名对象的方法，返回一个 ReducingSink 对象。</p>
</li>
<li>
<p>get(): 会等 <code>helper.wrapAndCopyInto</code> 执行完后取值</p>
</li>
</ul>
</div>
<div class="paragraph">
<p><strong>进入 <code>helper.wrapAndCopyInto</code> 中</strong>：</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java" data-lang="java">    @Override
    final &lt;P_IN, S extends Sink&lt;E_OUT&gt;&gt; S wrapAndCopyInto(S sink, Spliterator&lt;P_IN&gt; spliterator) {
        copyInto(wrapSink(Objects.requireNonNull(sink)), spliterator);
        return sink;
    }</code></pre>
</div>
</div>
<div class="ulist">
<ul>
<li>
<p>重点 ：<code>wrapSink(Objects.requireNonNull(sink))</code></p>
</li>
</ul>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java" data-lang="java">    @Override
    @SuppressWarnings("unchecked")
    final &lt;P_IN&gt; Sink&lt;P_IN&gt; wrapSink(Sink&lt;E_OUT&gt; sink) {
        Objects.requireNonNull(sink);
    // 这里就用到开头所属的depth作用。
        for ( @SuppressWarnings("rawtypes") AbstractPipeline p=AbstractPipeline.this; p.depth &gt; 0; p=p.previousStage) {
            sink = p.opWrapSink(p.previousStage.combinedFlags, sink);
        }
        return (Sink&lt;P_IN&gt;) sink;
    }</code></pre>
</div>
</div>
<div class="paragraph">
<p>最终的sink对象结构：</p>
</div>
<div class="imageblock">
<div class="content">
<img src="http://www.wanghengzhi.com/upload/2021/08/%E5%9B%BE%E7%89%87-7167575156724e3eb71b8464c5200713.png" alt="图片.png">
</div>
<div class="title">Figure 12. 图片.png</div>
</div>
<div class="paragraph">
<p>这里通过debug，依次遍历，可知创建顺序，现实创建了 1
标注点的downStream，然后赋值给sink，然后将sink传递给下一个，创建了 2
标注点的downStream，再次赋值给sink，依次往前套娃，直到depth等于0，便形成这样一个
sink
链。这是很重要的一个操作。如下图，红色箭头表示创建wrapperSink的顺序，并且容易理解到，从下到上遍历创建，最终形成上一图
1/2/3/4/5/6 这种结构，最下层的sink在最后。</p>
</div>
<div class="imageblock">
<div class="content">
<img src="http://www.wanghengzhi.com/upload/2021/08/%E5%9B%BE%E7%89%87-465bdd0eb0c746c69be3b50f9cfb40af.png" alt="图片.png">
</div>
<div class="title">Figure 13. 图片.png</div>
</div>
<div class="paragraph">
<p>Sink的作用：等价于每个流的操作，例如skip、sorted、map等等，形成wrapperSink这样嵌套结构，就是为了遍历元素，让元素按照sink链进行筛选，最终得到想要的结果。由此可知，以上所有操作都不涉及处理元素。</p>
</div>
<div class="paragraph">
<p><strong>真正处理元素的是 <code>copyInto</code> 方法：</strong></p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java" data-lang="java">    @Override
    final &lt;P_IN&gt; void copyInto(Sink&lt;P_IN&gt; wrappedSink, Spliterator&lt;P_IN&gt; spliterator) {
        Objects.requireNonNull(wrappedSink);

        if (!StreamOpFlag.SHORT_CIRCUIT.isKnown(getStreamAndOpFlags())) {
            wrappedSink.begin(spliterator.getExactSizeIfKnown());
            spliterator.forEachRemaining(wrappedSink);
            wrappedSink.end();
        }
        else {
            copyIntoWithCancel(wrappedSink, spliterator);
        }
    }</code></pre>
</div>
</div>
<div class="ulist">
<ul>
<li>
<p>wrappedSink ： 就是处理元素的层层条件</p>
</li>
<li>
<p>spliterator ： 也即待处理的元素</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>由此可知，前面的所有操作都是为了得到一个执行链 wrappedSink。
这里会进入if代码块中，只分析if。</p>
</div>
<div class="olist arabic">
<ol class="arabic">
<li>
<p>wrappedSink.begin(spliterator.getExactSizeIfKnown());</p>
</li>
</ol>
</div>
<div class="paragraph">
<p>通过debug进入begin，会发现依次调用了
stream2#Sink、stream3#sink、stream4#sink 就停止了（绿色箭头）。stream4
执行 sorted，查看源码会发现stream4#sink创建了一个list，便停止继续调用
downStream#begin 方法了。</p>
</div>
<div class="imageblock">
<div class="content">
<img src="http://www.wanghengzhi.com/upload/2021/08/%E5%9B%BE%E7%89%87-4edb86972d044e43992d031d38c93db8.png" alt="图片.png">
</div>
<div class="title">Figure 14. 图片.png</div>
</div>
<div class="olist arabic">
<ol class="arabic" start="2">
<li>
<p>spliterator.forEachRemaining(wrappedSink);</p>
</li>
</ol>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java" data-lang="java">// 这里只分析核心代码。从这可以看出，开始遍历处理元素了。
for (; i &lt; hi; ++i) {
   @SuppressWarnings("unchecked") E e = (E) a[i];
   action.accept(e);
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>同理通过源码分析可知，第一个元素 e,
调用第一个accept，发现这个是skip，e不符合规则，不操作，继续遍历第二个元素，同理，无法通过第一个
accept，直到第3个元素，可以通过第一个accept，然后进入第二个accept，第二个accept判断是否符合filter的Lambda表达式，不通过，不操作，通过则进入第3个accept，第三个accept，只做了一件事，就是把通过的元素e，放入begin链调用时创建的list中，因此可以知道此行代码进行的操作，是循环过滤符合第一个accept以及第二个accept的元素，并放入第三个accept中的list。</p>
</div>
<div class="imageblock">
<div class="content">
<img src="http://www.wanghengzhi.com/upload/2021/08/%E5%9B%BE%E7%89%87-7512534877074f98acd943e1c8c8bd37.png" alt="图片.png">
</div>
<div class="title">Figure 15. 图片.png</div>
</div>
<div class="olist arabic">
<ol class="arabic" start="3">
<li>
<p>wrappedSink.end();</p>
</li>
</ol>
</div>
<div class="paragraph">
<p>通过源码发现，当执行到第3个end时，也即 sorted sink
中的end，进行了list排序，也即</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java" data-lang="java">        @Override
        public void end() {
            list.sort(comparator);
            downstream.begin(list.size());
            if (!cancellationWasRequested) {
                list.forEach(downstream::accept);
            }
            else {
                for (T t : list) {
                    if (downstream.cancellationRequested()) break;
                    downstream.accept(t);
                }
            }
            downstream.end();
            list = null;
        }</code></pre>
</div>
</div>
<div class="ulist">
<ul>
<li>
<p>第一行代码，进行了排序。也即这个 sink 所要做的事</p>
</li>
<li>
<p>第二行，又开始调用begin了。源码可知，此begin就是第一次begin执行中止后的begin,值得注意的是，进入distinct#sink#begin中，创建了一个HashSet对象，同上面创建list一样，这里通过set来进行distinct操作，最后一个begin则设置了如何获取目标元素。</p>
</li>
<li>
<p>if/else
又开始调用剩余accept函数，依次进行元素操作。可以看出，这里的循环对象是，上一次产生的list，已经执行过前3个accept操作了。</p>
</li>
<li>
<p>accept 执行完成后，又开始执行剩余的end操作。</p>
</li>
<li>
<p>复制list = null，垃圾收集器回收，感悟：不用的对象，即使进行回收。</p>
</li>
</ul>
</div>
<div class="paragraph">
<p><strong>至此，整个执行流程应当如下：</strong></p>
</div>
<div class="imageblock">
<div class="content">
<img src="http://www.wanghengzhi.com/upload/2021/08/%E5%9B%BE%E7%89%87-ed877086e5fe4880b0e00f6f1b0c769e.png" alt="图片.png">
</div>
<div class="title">Figure 16. 图片.png</div>
</div>
<div class="paragraph">
<p>大致可以得出：</p>
</div>
<div class="ulist">
<ul>
<li>
<p>依次调用begin链、accept链、end链。</p>
</li>
<li>
<p>如果begin链发生中断，则调用accept链，在相同的sink中也会中断，然后执行end链，由end链再次发起
being链-accept链-end链流程。</p>
</li>
<li>
<p>为什么会发生中断？这里以sorted进行说明。当遇到 sorted
sink时，后面的sink操作必须等待排序完成后才能操作，也即 end
操作后。说简单点就是后面的操作必须依赖上一步操作执行完，才能正确处理。</p>
</li>
<li>
<p>推论出，如果一个流中，包含多个中断操作流，那么一定会进行多个
being链-accept链-end链流程 ，而不是一个。</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>最后的最后，处理完成后，会通过最后一个sink的get操作获取目标对象，目标对象放在
Box 类中的 state 属性。</p>
</div>
<div class="paragraph">
<p><strong>总结一下：</strong></p>
</div>
<div class="olist arabic">
<ol class="arabic">
<li>
<p>整个流为双向链表，直到一个结束流来进行处理。</p>
</li>
<li>
<p>通过将链表流中的 sink 操作包装起来，形成调用链。</p>
</li>
<li>
<p>然后将元素依次执行 sink
链的操作，每一个sink包含begin、accept、end操作，sink会出现中断和不中断2种情况，所以sink分2大类，也即对应流的stage分2大类，
stagelessOp/stagefulOp。</p>
</li>
<li>
<p>最终将数据放入，最后生成的结束流中。</p>
</li>
</ol>
</div>
<div class="paragraph">
<p><strong>java.lang.stream 包介绍</strong></p>
</div>
<div class="paragraph">
<p>流的相关类</p>
</div>
<div class="imageblock">
<div class="content">
<img src="http://www.wanghengzhi.com/upload/2021/08/%E5%9B%BE%E7%89%87-2a8a8b0a9bb243049da864131e72d51c.png" alt="图片.png">
</div>
<div class="title">Figure 17. 图片.png</div>
</div>
<div class="paragraph">
<p>关键字：</p>
</div>
<div class="ulist">
<ul>
<li>
<p>stream：流，抽象接口</p>
</li>
<li>
<p>pipeline: 管道，也即一个流的具体实现，每个流对应响应流的操作。</p>
</li>
<li>
<p>ops：具体操作流，例如查找、匹配等</p>
</li>
<li>
<p>sink： 执行Lambda表达式的链路</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>分类：</p>
</div>
<div class="imageblock">
<div class="content">
<img src="http://www.wanghengzhi.com/upload/2021/08/%E5%9B%BE%E7%89%87-a0e36302d986439c8058516a520c8b63.png" alt="图片.png">
</div>
<div class="title">Figure 18. 图片.png</div>
</div>
<div class="ulist">
<ul>
<li>
<p>从结构中，可知，核心类都是抽象类以及接口内，不能直接实例化对象，因此在很多代码内部都是创建匿名类来生成对应的对象。</p>
</li>
<li>
<p>主要流接口由 Stream、LongStream、IntStream、DoubleStream</p>
</li>
<li>
<p>每个流接口，都有一个抽象pipeline类实现。</p>
</li>
<li>
<p>每个pipeline实现抽象类中，都有3个静态内部抽象类
Head、StagefulOp、StagefulOp，并且它们都继承外部的pipeline抽象类。</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>从 Stream 类开始</p>
</div>
<div class="paragraph">
<p>先知晓2个概念，从Stream接口中的方法的注释，会标注这个方法是属于</p>
</div>
<div class="ulist">
<ul>
<li>
<p>This is an <code>intermediate</code> operation.
这是一个中间操作，会产生一个新的流，其返回值必是一个流。（执行步骤）</p>
</li>
<li>
<p>This is a <code>terminal</code> operation.
这是一个终止操作，会结束整个流，其返回值不再是流，而是期望的结果。（结果）</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>中间操作有2个类型，stageless、stageful</p>
</div>
<div class="ulist">
<ul>
<li>
<p>StatelessOp: 表示这个操作会</p>
</li>
<li>
<p>StatefulOp:</p>
</li>
</ul>
</div>
<div class="imageblock">
<div class="content">
<img src="http://www.wanghengzhi.com/upload/2021/08/%E5%9B%BE%E7%89%87-760d3ab2b36245edbd2c37580130e11e.png" alt="图片.png">
</div>
<div class="title">Figure 19. 图片.png</div>
</div>
<div class="paragraph">
<p>映射类（返回值均为流，表明是中间操作，其主要目的是将元素转换成目标类型。）：</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java" data-lang="java">&lt;R&gt; Stream&lt;R&gt; map(Function&lt;? super T, ? extends R&gt; mapper);

IntStream mapToInt(ToIntFunction&lt;? super T&gt; mapper);

LongStream mapToLong(ToLongFunction&lt;? super T&gt; mapper);

DoubleStream mapToDouble(ToDoubleFunction&lt;? super T&gt; mapper);

&lt;R&gt; Stream&lt;R&gt; flatMap(Function&lt;? super T, ? extends Stream&lt;? extends R&gt;&gt; mapper);

IntStream flatMapToInt(Function&lt;? super T, ? extends IntStream&gt; mapper);

LongStream flatMapToLong(Function&lt;? super T, ? extends LongStream&gt; mapper);

DoubleStream flatMapToDouble(Function&lt;? super T, ? extends DoubleStream&gt; mapper);</code></pre>
</div>
</div>
<div class="paragraph">
<p>筛选和切片：</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java" data-lang="java">Stream&lt;T&gt; filter(Predicate&lt;? super T&gt; predicate);

Stream&lt;T&gt; distinct();

Stream&lt;T&gt; sorted();

Stream&lt;T&gt; sorted(Comparator&lt;? super T&gt; comparator);

Stream&lt;T&gt; limit(long maxSize);

Stream&lt;T&gt; skip(long n);

Optional&lt;T&gt; min(Comparator&lt;? super T&gt; comparator);

Optional&lt;T&gt; max(Comparator&lt;? super T&gt; comparator);

&lt;T&gt; Stream&lt;T&gt; concat(Stream&lt;? extends T&gt; a, Stream&lt;? extends T&gt; b)</code></pre>
</div>
</div>
<div class="paragraph">
<p>循环：</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java" data-lang="java">Stream&lt;T&gt; peek(Consumer&lt;? super T&gt; action);

void forEach(Consumer&lt;? super T&gt; action);

void forEachOrdered(Consumer&lt;? super T&gt; action);

void forEachOrdered(Consumer&lt;? super T&gt; action);</code></pre>
</div>
</div>
<div class="paragraph">
<p>查找：</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java" data-lang="java">boolean anyMatch(Predicate&lt;? super T&gt; predicate);

boolean allMatch(Predicate&lt;? super T&gt; predicate);

boolean noneMatch(Predicate&lt;? super T&gt; predicate);

Optional&lt;T&gt; findFirst();

Optional&lt;T&gt; findAny();</code></pre>
</div>
</div>
<div class="paragraph">
<p>收集、转为结果：</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java" data-lang="java">Object[] toArray();

&lt;A&gt; A[] toArray(IntFunction&lt;A[]&gt; generator);

T reduce(T identity, BinaryOperator&lt;T&gt; accumulator);

Optional&lt;T&gt; reduce(BinaryOperator&lt;T&gt; accumulator);

&lt;U&gt; U reduce(U identity,
                 BiFunction&lt;U, ? super T, U&gt; accumulator,
                 BinaryOperator&lt;U&gt; combiner);

&lt;R&gt; R collect(Supplier&lt;R&gt; supplier,
                  BiConsumer&lt;R, ? super T&gt; accumulator,
                  BiConsumer&lt;R, R&gt; combiner);

&lt;R, A&gt; R collect(Collector&lt;? super T, A, R&gt; collector);</code></pre>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_lambda">1.15. Lambda</h3>
<div class="paragraph">
<p>记录下个人见解：</p>
</div>
<div class="paragraph">
<p><strong>从一个常见的例子认识Lambda表达式</strong></p>
</div>
<div class="paragraph">
<p>启动一个线程执行一个任务： 原始写法：</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java" data-lang="java">public class Lambda {
    public static void main(String[] args) {
        new Thread(new MyTask());

    }
}

class MyTask implements Runnable {
    @Override
    public void run() {
        // do something
        System.out.println("这是任务1");
    }
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>步骤： - 创建一个实现类，实现Runable接口。 -
并重写run方法，里面的代码也即需要新开线程实现的功能。 - 使用new
Thread(),创建线程，并将任务MyTask创建一个对象，放入Thread对象中。</p>
</div>
<div class="paragraph">
<p>那么问题来了，如果我有很多task，例如task1、task2、task3…，那么我们就要创建很多类，MyTask1…MyTaskN，然而这些MyTaskN，很多时候是无意义的，我们的目标只是执行一段代码而已，并不想创建类，增加维护复杂度。</p>
</div>
<div class="paragraph">
<p>总结下，我（代码）需要一个对象，并调用对象的指定方法。我不管这个对象的实现，我只需要定义一个接口，并定义好我需要调用的方法，你只负责实现这个接口，然后传递给我，我来执行调用。</p>
</div>
<div class="paragraph">
<p>再抽象下，这里创建新线程，执行新任务，本质上就是<strong>执行一段代码</strong>，但是java不支持代码段参数，所以需要将这段代码放在一个对象中，并协议好调用方法，自己手动创建一个Runable对象，run方法便是调用的方法。</p>
</div>
<div class="paragraph">
<p>如果不创建Runable的实现类，有什么其他办法实现呢？有，使用匿名类。</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java" data-lang="java">        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("只是一个任务！");
            }
        });</code></pre>
</div>
</div>
<div class="paragraph">
<p>不够简洁，简写，定义新的符号 <code>-&gt;</code>。</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java" data-lang="java">new Thread(() -&gt; System.out.println("只是一个任务！"));</code></pre>
</div>
</div>
<div class="paragraph">
<p>可以看出，Lambda表达式实际就是创建了一个匿名函数。下面分析下构造。</p>
</div>
<div class="ulist">
<ul>
<li>
<p><code>()</code>
常规java参数，这里无参（实际参数，不需要类型，只需要值即可，类型可由上下文推断出来。（a,
b）&#8594; xxx , a, b都是参数值，不用定义类型）</p>
</li>
<li>
<p><code>-&gt;</code>
推导这是一个Lambda表达式，需要根据Thead类，推断出是哪一个接口的匿名实现类，这里是Runable。</p>
</li>
<li>
<p><code>System.out.println("只是一个任务！")</code>
执行代码段，只有一行代码，可以省略`{}<code>和分号（;），
如果多行，就用</code>{}`包裹起来,并且使用分号（;） 。</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>至此，基本已表示清楚，需要注意一点，如何推导出类型的：</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java" data-lang="java">// 1
Runnable runnable = () -&gt; System.out.println("只是一个任务！");
// 正确
new Thread(runnable);

// 2
VoidFunc0 other = () -&gt; System.out.println("只是一个任务！");
// 错误
new Thread(other);

// 3 正确
new Thread(() -&gt; {
    System.out.println("只是一个任务！");
});</code></pre>
</div>
</div>
<div class="paragraph">
<p>从1、2可以看出，同一Lambda表达式，类型可以不同。也从侧面印证了Lambda表达式只是符合特定规律的一类表达式，返回类型可以自己定义，只要符合这个规则。这里不能推导出类型是Runable还是VoidFun0，说以需要指定类型。</p>
</div>
<div class="paragraph">
<p>从3可以知道，这里使用Thread的一个有参构造器，参数类型是Runable，故Lambda可以根据上下问推断出这个表达式类型是Runable的。</p>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_分析下lambda表达式创建条件">2. 分析下Lambda表达式创建条件</h2>
<div class="sectionbody">
<div class="paragraph">
<p>有前面可知Lambda表达式是为了消除创建实现类，然后在进行创建对象当做参数。Runable以及VoidFunc0均为接口，由Lambda表达式进行实现。并且同一个表达式，可以有不同的类型接收。现在来看一看为何。</p>
</div>
<div class="paragraph">
<p><strong>源码：</strong></p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java" data-lang="java">@FunctionalInterface
public interface Runnable {
    public abstract void run();
}


package cn.hutool.core.lang.func;

/**
 * 函数对象&lt;br&gt;
 * 接口灵感来自于&lt;a href="http://actframework.org/"&gt;ActFramework&lt;/a&gt;&lt;br&gt;
 * 一个函数接口代表一个一个函数，用于包装一个函数为对象&lt;br&gt;
 * 在JDK8之前，Java的函数并不能作为参数传递，也不能作为返回值存在，此接口用于将一个函数包装成为一个对象，从而传递对象
 *
 * @author Looly
 *
 * @since 3.2.3
 */
@FunctionalInterface
public interface VoidFunc0 {
    void call() throws Exception;
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>共同点，都是有一个@FunctionalInterface注解，该注解的作用是标识此接口可用于Lambda表达式。那么什么样的接口可以用此注解标识呢？</p>
</div>
<div class="paragraph">
<p>通过JDK8源码javadoc，可以知道这个注解有以下特点： -
该注解只能标记在”有且仅有一个抽象方法”的接口上。 -
JDK8接口中的静态方法和默认方法，都不算是抽象方法。 -
接口默认继承java.lang.Object，所以如果接口显示声明覆盖了Object中方法，那么也不算抽象方法。
-
该注解不是必须的，如果一个接口符合”函数式接口”定义，那么加不加该注解都没有影响。加上该注解能够更好地让编译器进行检查。如果编写的不是函数式接口，但是加上了@FunctionInterface，那么编译器会报错。</p>
</div>
<div class="paragraph">
<p>注：符合这4点的接口，即使不使用 @FunctionalInterface
注解，也可用于创建Lambda表达式，加上这个只是为了编译器检测，如果错误，会给出提示。类似于
@Override 。</p>
</div>
<div class="paragraph">
<p>为何只能有一个抽象方法？</p>
</div>
<div class="paragraph">
<p><code>() -&gt; System.out.println("只是一个任务！");</code></p>
</div>
<div class="paragraph">
<p>可以近似理解，将这段代码视为抽象方法的实现。</p>
</div>
<div class="paragraph">
<p>扩展，通过创建自己的函数式接口，来体会Lambda表达式。</p>
</div>
<div class="paragraph">
<p>无参的形式</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java" data-lang="java">@FunctionalInterface
public interface MyNoArgsLambda {

    void doSomething();

}

public class MyNoArgsLambdaTest {
    public static void main(String[] args) {
        MyNoArgsLambda lambda = () -&gt; System.out.println("You are ...");
        lambda.doSomething();
    }
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>控制台，会输出 <code>You are ...</code>
Lambda表达式会生成一个对象，其实现了MyNoArgsLambda接口，并重写了`doSomething`方法，方法内容即为表达式内容。</p>
</div>
<div class="paragraph">
<p>单个参数</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java" data-lang="java">@FunctionalInterface
public interface SingleArgLambda {
    void doSomething(String arg);
}</code></pre>
</div>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java" data-lang="java">public class SingleArgLambdaTest {
    public static void main(String[] args) {
        SingleArgLambda lambda = e -&gt; System.out.println("you are " + e);
        lambda.doSomething("big");
    }
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>控制台输出：<code>you are big</code>。
这里有一个参数e，不需要加括号（e）&#8594;，不需要指定类型，会从SingleArgLambda推断出。</p>
</div>
<div class="paragraph">
<p>多个参数</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java" data-lang="java">@FunctionalInterface
public interface MultiArgsLambda {
    void doSomething(String a, int b, int c);
}</code></pre>
</div>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java" data-lang="java">public class MultiArgsLambdaTest {
    public static void main(String[] args) {
        MultiArgsLambda lambda = (a, b, c) -&gt; System.out.println(a + (b/c));
        lambda.doSomething("多参数除法：", 10, 2);
    }
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>控制台输出：<code>多参数除法：5</code>。
这里abc随便定义，也可以是xyz，类型对应MultiArgsLambda#doSomething的参数类型。</p>
</div>
<div class="sect2">
<h3 id="_日期">2.1. 日期</h3>
<div class="paragraph">
<p>有趣的科学知识</p>
</div>
<div class="paragraph">
<p>一天只有23时56分4秒，为什么钟表时间都显示24小时？</p>
</div>
<div class="paragraph">
<p><a href="https://baijiahao.baidu.com/s?id=1634476334025885195&amp;wfr=spider&amp;for=pc" class="bare">https://baijiahao.baidu.com/s?id=1634476334025885195&amp;wfr=spider&amp;for=pc</a></p>
</div>
<div class="paragraph">
<p>GMT: 格林威治时间</p>
</div>
<div class="paragraph">
<p>UTC:</p>
</div>
<div class="paragraph">
<p>UTC协调世界时即格林威治平太阳时间，是指格林威治所在地的标准时间，也是表示地球自转速率的一种形式，UTC基于国际原子时间</p>
</div>
</div>
<div class="sect2">
<h3 id="_jdk1_8之前">2.2. jdk1.8之前</h3>
<div class="paragraph">
<p>主要是 Date、Calendar、TimeZone类。</p>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_jdk1_8之后">3. jdk1.8之后</h2>
<div class="sectionbody">
<div class="paragraph">
<p>主要是 java.uitl.time 包内。</p>
</div>
</div>
</div>
</div>
<div id="footer">
<div id="footer-text" style="text-align: center;">
<a href="https://beian.miit.gov.cn">蜀 ICP 备 2024094310 号</a> | <a href="http://www.beian.gov.cn/portal/registerSystemInfo?recordcode=51160302511654">川公网安备 51160302511654 号</a>  | 联系邮箱: zerothreeoneone@foxmail.com | 
更新于 2024-08-22 22:37:18 CST
</div>
</div>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/8.9.1/styles/github.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/8.9.1/highlight.min.js"></script>
<script>hljs.initHighlighting()</script>
</body>
</html>